AVR032: командные файлы линкера для компилятора IAR ICCA90
Добавил(а) microsin
В даташите AVR032 рассматриваются следующие вопросы:
• Команды линкера XLINK • Размещение сегментов и объяснение их смысла • Примеры командных файлов линкера для: – микроконтроллера AT90S2313 – микроконтроллера AT90S8515 – микроконтроллера AT90S8515 с подключенным внешним ОЗУ (External RAM) и памятью с привязкой к вводу/выводу (Memory Mapped I/O)
Этот апноут показывает, как сделать командный файл для линкера при использовании C-компилятора IAR ICCA90 для микроконтроллеров AVR®.
Компилятор C преобразует исходный код в объектный, который может быть выполнен микроконтроллером. Этот код обычно делится на модули, в которых есть блоки кода и блоки данных. Вывод компилятора (объектные файлы) содержат перемещаемый код - это означает, что у него пока нет привязки к абсолютным адресам в пространствах памяти программ и данных.
Когда код линкуется (это слово пошло от английского link, что означает "соединять"), то инструкции микроконтроллера получают привязку к действительным рабочим адресам в памяти микроконтроллера (в этом апноуте рассматривается линкер XLINK компании IAR). Линкер также соединяет друг с другом несколько объектных модулей программы, и также присоединяет код из внешних, заранее скомпилированных библиотек (отсюда и пошло название - linker). XLINK берет из внешней библиотеки только те куски кода, которые используются в программе пользователя. Выходные файлы XLINK представляют исполняемый код, который может быть загружен в память FLASH микроконтроллера, или выполнен в симуляторе AVR Studio.
Для управления поведением XLINK пользователь пишет командный файл, который содержит последовательность специальных инструкций для XLINK. Вместе с IAR Embedded Workbench поставляется набор стандартных командных файлов XLINK для различных размеров памяти. Эти файлы основаны на предположениях, которые могут не отвечать действительности, поэтому иногда требуется применение скорректированного командного файла линкера. Кроме того, даже если предположения командного файла верны, модификация файла в большинстве случаев позволит улучшить утилизацию памяти программой.
Этот апноут описывает, как сделать свой собственный файл команд для микроконтроллеров AVR. Чтобы сделать файл для XLINK, используйте текстовый редактор. Сохраните файл в каталог проекта и дайте файлу расширение .XCL, например mylink.xcl. Чтобы использовать файл линкера в IAR Embedded Workbench, зайдите в свойства проекта (project -> options), перейдите в раздел XLINK -> include. Выберите "override default", где указывается имя XCL-файла линкера, и выберите новый файл с расширением .xcl.
[Команды XLINK]
В этой секции кратко рассмотрены основные команды линкера XLINK, которые чаще всего используются в XCL-файле команд. Все адреса и размеры указываются в шестнадцатеричном формате. Чтобы получить полное руководство по командам линкера, см. руководство IAR Assembler Users Guide, раздел XLINK options.
Комментарии. Они служат для того, чтобы пояснять содержимое файла команд. Комментарии начинаются и заканчиваются символами -!. Пример:
-! Это просто комментарий -!
Тип CPU, директива -c. Команда задает, какую использовать архитектуру. Файл команд линкера всегда начинается с этой команды.
-c< тип_cpu >
Пример:
-ca90
Здесь задано использование архитектуры AVR.
Определение сегментов, директива -Z. Эта команда определяет сегменты в памяти микроконтроллера.
В этом примере задано два сегмента в памяти FLASH (память программ). Сегмент RCODE начнется с адреса 1C (адрес указан в HEX-формате), и за сегментом RCODE сразу начнется сегмент CDATA0. Если общий размер этих сегментов превысит предоставленное пространство, то будет выдано сообщение об ошибке.
Еще пример:
-Z(DATA)IDATA1,UDATA1,ECSTR,CSTACK+40=120-25F
Здесь задаются сегменты в памяти RAM (оперативная память). Сегмент IDATA1 начнется с адреса 120, и за ним будут идти сегменты UDATA1 и ECSTR. Выражение CSTACK + 40 означает, что сегмент CSTACK начнется с адреса, равного концу сегмента ECSTR плюс 40 (указано в HEX, что равно 64 десятичному). Так сделано потому, что стек растет в обратном направлении, т. е. в сторону уменьшения адреса (тут зарезервировано 64 байта под стек).
Определение имени замены для внешнего символа, директива -e.
-eзаменяющее_имя
Пример:
-e_small_write=_formatted_write
В этом примере внешняя стандартная подпрограмма _formatted_write будет заменена уменьшенной версией _small_write. Это часто делают для функций чтения и записи scanf() и printf(), поскольку стандартные подпрограммы ввода и вывода ANSI очень сложны и в результате дают большой объем кода.
Запрет предупреждающих сообщений, директива -w. Позволяет запретить вывод предупреждающего сообщения (warning) с определенным номером.
-wномер
Пример:
-w29
В этом примере запрещено выдавать Warning номер 29.
[Что такое сегменты]
Сегменты - это просто именованные куски памяти определенного типа. Для AVR есть следующие типы памяти:
• Program memory. Память программ, FLASH. Тип памяти CODE. Она содержит сегменты только для чтения. Если это программа, то обычно здесь расположено несколько сегментов, как минимум 1 сегмент. • Internal RAM. Внутренняя оперативная память, SRAM, содержит в себе несколько сегментов для чтения и записи. Если это программа, то обычно имеется как минимум 2 сегмента - для данных и стека. • External Memory. Внешняя память, которая подключается через внешнюю аппаратную шину. Применяется довольно редко. Эта память может быть разного физического типа: SRAM, EPROM, EEPROM, или memory-mapped I/O.
Ниже рассматриваются разные типы памяти и сегменты. Пользователь может также сам задавать сегменты, и разместить в них переменные в определенном месте памяти. В каждом типе памяти может быть несколько сегментов.
[Сегменты в памяти программ]
Все сегменты памяти программ работают только для чтения. Это обычно память FLASH, расположенная внутри микроконтроллера AVR.
Примечание: линкер XLINK всегда считает размеры сегментов в байтах, хотя счетчик адреса программ AVR считает в словах. 1 слово соответствует 2 байтам, и часто кодирует 1 инструкцию (хотя есть инструкции, состоящие из 2 слов).
INTVEC. В этом сегменте содержится адреса для сброса и обработчиков прерываний (так называемые вектор Reset и вектора Interrupt) микроконтроллера. Обычно этот сегмент начинается с адреса 0, т. е. находится в самом начале памяти программ.
Примечание: некоторые современные AVR, например серии ATmega, могут иметь настраиваемый вектор сброса, что задается фьюзами. Т. е. вектор сброса может начинаться не с нулевого адреса, а с другого определенного, который находится ближе к последним страницам памяти программ. Это используется для так называемого загрузчика кода (bootloader).
Для микроконтроллеров, которые имеют память программ 8 килобайт и меньше, каждый вектор прерывания содержит инструкцию RJUMP (Relative Jump, переход относительно текущего адреса), которая имеет длину 2 байта (1 слово). Для микроконтроллеров, у которых память программ больше 8 килобайт, каждый вектор уже хранит инструкцию JMP (Jump, переход по абсолютному адресу), которая имеет длину 4 байта (2 слова). Подробности см. в документации на микроконтроллер, где описана обработка векторов сброса и прерываний.
Размер сегмента INTVEC должен быть задан пользователем. Например, для микроконтроллера AT90S8515 этот сегмент размещен по адресам 0-1B. Это дает 28 ячеек памяти, которых достаточно для хранения вектора сброса и 13 векторов прерываний. Пример:
-Z(CODE)INTVEC=0-1B
RCODE. Этот сегмент содержит код, в который может передать управление инструкция RJUMP из сегмента INTVEC. Так называемый код запуска C-STARTUP всегда расположен в сегменте RCODE. Код C-STARTUP выполняет низкоуровневую инициализацию микроконтроллера для программы на языке C:
• Инициализация указателей стека для данных и программы. • Инициализация глобальных и статических переменных. • Вызов функции main().
CDATA0, CDATA1, CDATA2, CDATA3. Содержат константы инициализации для данных (т. е. инициализированных переменных) tiny, small, far и huge соответственно. При старте код startup копирует эти сегменты в сегменты оперативной памяти IDATA0, IDATA1, IDATA2, IDATA3 (см. далее). Размеры этих сегментов вычисляются линкером XLINK. Пример инициализированной переменной:
char i =0; /* Глобальная переменная языка C */
CCSTR. Содержит строковые литералы C (константы с текстом). При старте код startup копирует этот сегмент в сегмент ECSTR, находящийся в SRAM. Размер этого сегмента вычисляет XLINK.
FLASH. Содержит константы, которые декларированы с типом flash. Для доступа к этим константам в программе на C компилятор задействует инструкцию LPM. Размер сегмента FLASH вычисляет XLINK. Пример кода на языке C, который задает константу в виде массива символов, размещаемую в сегменте FLASH:
flash char mystring[] ="Эта строка находится в памяти flash";
SWITCH. Содержит таблицы переходов, сгенерированные для операторов switch. Размер этого сегмента вычисляется XLINK.
CODE. Содержит код программы. Размер этого сегмента вычисляется XLINK. Декларирование сегментов в памяти программ происходит просто. Важны 2 параметра: размер таблицы векторов прерываний, и размер памяти программ в микроконтроллере. Для декларирования сегментов памяти программ достаточно использовать следующие 2 строки:
-Z(CODE)INTVEC=0-Interrupt vector size(bytes)
-Z(CODE)RCODE,CDATA0,CDATA1,CCSTR,SWITCH,FLASH,CODE=размер таблицы прерываний
(в байтах)-конец памяти программ (байтовый адрес)
Эти 2 строки создадут карту памяти, показанную ниже (Program Memory Map - распределение сегментов, карта памяти программ).
INTVEC
RCODE
CDATA0
CDATA1
CCSTR
SWITCH
FLASH
CODE
[Сегменты в памяти данных]
Память данных состоит из внутренней и внешней оперативной памяти (RAM, или SRAM). Переменные в RAM работают и на чтение, и на запись. Регистровый файл из 32 регистров (так называемые general purpose registers, регистры общего назначения) привязаны к адресам RAM 0-1F, 64 регистра ввода/вывода (I/O registers) привязаны к адресам 20-5F. Таким образом, внутренняя память (Internal SRAM) начинается с адреса 60 (HEX). Начальный адрес внешней памяти (External SRAM) зависит от модели микроконтроллера. На рисунке ниже показана Data Memory Map - карта памяти данных.
Далее будут рассмотрены сегменты, размещаемые в памяти данных.
UDATA0, UDATA1, UDATA2, UDATA3. Неинициализированные данные для переменных tiny, small, far и huge соответственно. Эти сегменты содержат место для переменных, которые не инициализированы при декларировании. Размер этого сегмента либо задается пользователем, либо он вычисляется линкером XLINK автоматически. Рекомендуется использовать автоматическое вычисление.
IDATA0, IDATA1, IDATA2, IDATA3. То же самое, но уже для инициализированных при декларировании переменных. Переменные, находящиеся в сегментах IDATA, копируются из соответствующих сегментов CDATA при запуске программы кодом startup. Размер этого сегмента либо задается пользователем, либо он вычисляется линкером XLINK автоматически. Рекомендуется использовать автоматическое вычисление.
Если активна опция компилятора -y (writable strings, записываемые строки), то объекты констант (переменные с атрибутом const) будут копироваться в сегмент IDATA из сегмента CDATA при запуске программы кодом startup.
Примечание: переменные, декларированные как tiny, будут размещены в сегментах UDATA0 и IDATA0. К переменным tiny может быть осуществлен доступ с помощью 8-разрядного адреса (первые 256 байт, адреса 0-FF). Код, работающий с переменными tiny, работает быстрее всего, и занимает в памяти программ меньше всего места. Так как ожидается, что к памяти привязаны адреса регистрового файла (General Purpose Registers) и регистры ввода/вывода (I/O Registers), то переменные tiny не должны размещаться по адресам, меньшим чем 60 (HEX, в десятичном формате это будет 96), и не должны размещаться по адресам, больше чем FF (HEX, в десятичном формате это будет 255).
Пример декларирования переменной tiny на языке C, которая попадет в сегмент UDATA0:
tiny int temp;
Есть несколько способов для установки сегментов для переменных tiny. Вот один пример:
-Z(DATA)IDATA0,UDATA0=60-FF
Это выделяет адресное пространство RAM между адресами 60 и FF (HEX) для переменных tiny. Обратите внимание, что здесь зарезервировано все адресное пространство от адреса 60 до адреса FF включительно, даже если программа не использует переменных tiny! Если программа использует слишком много переменных tiny, чем для них хватит этого места, то пользователь получит сообщение об ошибке на этапе линковки.
Здесь переменные tiny будут помещены в младшие адреса внутреннего адресного пространства RAM, и за ними сразу идет сегмент RSTACK. Не будет потеряно лишнего пространства памяти, если есть мало переменных tiny. Однако не будет выдано предупреждающее сообщение, если в программе будет слишком много переменных tiny, так что размер сегментов IDATA0/UDATA0 превысит адрес FF (HEX).
Остерегайтесь непредсказуемого поведения программы, если переполнится адресное пространство сегментов IDATA0/UDATA0 для этого случая, для чего внимательно изучите выходной листинг карты памяти линкера (linker map file) - чтобы определить реальный размер памяти, который требуется для переменных tiny.
RSTACK. Стек возвратов (Return Stack), он содержит адреса возврата из подпрограмм и функций. Для доступа к этому стеку используется специальный 16-битный регистр, указатель стека (Stack Pointer). Размер сегмента RSTACK зависит от приложения. Каждый вызов функции требует для резервирования в стеке 2 байт - для адреса возврата. Адреса возврата из обработчика прерывания также сохраняются в Return Stack. Если декларирован слишком маленький размер стека, то стек может перезаписать другой сегмент в области памяти данных (могут запортиться переменные или регистры) - эта ситуация называется переполнение стека возврата.
ECSTR. Этот сегмент содержит записываемые копии строковых литералов языка C, если активна опция -y (writable strings) компилятора. Содержимое этого сегмента при запуске программы копируется кодом startup из сегмента CCSTR (находится в области памяти CODE). Если имеется нехватка памяти данных, то проверьте, созданы ли строки как константы, и для минимизации затрат памяти данных используйте вместо этого декларации с атрибутом flash.
CSTACK. Стек для данных (Data Stack). Архитектура AVR, в отличие от многих других архитектур CPU (в которых под локальные данные используется стек возврата), имеет для данных отдельный стек, используемый под локальные данные. Для доступа к этому стеку используется указатель Y (регистровая пара R28-R29). Размер сегмента CSTACK зависит от приложения. В стеке CSTACK хранятся локальные переменные и параметры функции, временные значения, и сюда же сохраняются регистры в обработчике прерывания. Если размер сегмента стека данных CSTACK слишком мал, то стек данных может перезаписать другие сегменты в области памяти данных (могут запортиться переменные или регистры) - эта ситуация называется переполнение стека данных.
[Сегменты External PROM]
Предупреждение: если не активна опция -y (writable strings), то поведение по умолчанию приведет к тому, что компилятор наличие в системе external PROM. В большинстве случаев в системе нет external PROM, и опция writable string должна быть активна. Чтобы минимизировать потери памяти данных, рекомендуется для констант использовать ключевое слово flash. Пример:
flash char mystring[] ="Строка в памяти flash";
Следующие сегменты только для чтения размещаются в external PROM.
CONST. В этом сегменте содержатся переменные, декларированные как const.
CSTR. Содержит строковые литералы, когда опция -y (writable strings) не активна.
Примечание: сегменты CONST и CSTR должны быть заданы только в файле XLINK, если в системе имеется external PROM.
[Сегменты, определенные пользователем]
Пользователь может сам задать сегменты, и привязать к ним переменные, тем самым разместить переменные в нужные абсолютные адреса памяти. Например, часы реального времени (Real Time Clock, RTC) размещены во внешней памяти по абсолютному адресу. Для доступа к адресам часов создан сегмент RTC:
-Z(DATA)RTC=0F00-0F70
Пример кода C, который размещает переменные в сегмент RTC, т. е. к памяти, привязанной к вводу/выводу (memory mapped I/O):
Пример показывает использование AT90S2313 с 2 килобайт памяти FLASH и 128 байтами внутреннего RAM. Все сегменты будут установлены, как показано на карте памяти рисунка (см. ниже). В памяти программ (CODE) только для сегмента INTVEC заданы определенные адреса. Другие сегменты будут размещены в последующих адресах, в том порядке, как они появляются в файле команд линкера. Для RAM указан только порядок следования сегментов, никакие абсолютные адреса для сегментов не указаны.
-! Командный файл XLINK для AT90S2313, имеющего 128 байт для данных (адресное
пространство 60-DF) и 2 килобайта для кода программ (0-7FF). -!
-! Здесь задан тип процессора (AVR) -!
-ca90
-! Определение сегмента для векторов сброса и обработчиков прерывания, для
которого требуется 22 (десятичное число) ячейки памяти -!
-Z(CODE)INTVEC=0-15
-! Определение сегментов в памяти flash -!
-Z(CODE)RCODE,CDATA0,CCSTR,SWITCH,FLASH,CODE=16-7FF
-! Определение сегментов в RAM. Регистровый файл находится в ячейках 0-1F,
memory mapped I/O в ячейках 20-5F, встроенное SRAM в 60-DF. -!
-! Размер стека возвратов 16 байт (10 hex), размер стека данных 64 байта
(40 hex) -!
-Z(DATA)IDATA0,UDATA0,RSTACK+10,ECSTR,CSTACK+40=60-DF
-! Выбор урезанной версии printf, чтобы уменьшить размер кода, подключаемого
из библиотек. См. секцию конфигурирования в руководстве IAR C-compiler
Users Guide, касающейся использования printf/sprintf. -!
-e_small_write=_formatted_write
-e_small_write_P=_formatted_write_P
-! Запрет поддержки операций с плавающей точкой в scanf, чтобы уменьшить размер
кода, подключаемого из библиотек. См. секцию конфигурирования в руководстве
IAR C-compiler Users Guide, касающейся использования scanf/sscanf -!
-e_medium_read=_formatted_read
-e_medium_read_P=_formatted_read_P
-! Подавления warning-а, который не относится к данному типу процессора -!
-w29
-! Загрузка C-библиотеки для модели памяти tiny, опция процессора option_V0 -!
cl0t
Пример показывает использование AT90S8515 с 8 килобайт памяти FLASH и 512 байтами внутреннего RAM. Все сегменты будут установлены, как показано на карте памяти рисунка (см. ниже). В памяти программ (CODE) только для сегмента INTVEC заданы определенные адреса. Другие сегменты будут размещены в последующих адресах, в том порядке, как они появляются в файле команд линкера. Для RAM указан только порядок следования сегментов, никакие абсолютные адреса для сегментов не указаны.
-! Командный файл XLINK для AT90S8515, имеющего 512 байт для данных
и 8 килобайт для кода программ. -!
-! Здесь задан тип процессора (AVR) -!
-ca90
-! Определение сегмента для векторов сброса и обработчиков прерывания, для
которого требуется 28 (десятичное число) ячеек памяти -!
-Z(CODE)INTVEC=0-1B
-! Определение сегментов в памяти flash -!
-Z(CODE)RCODE,CDATA0,CDATA1,CCSTR,SWITCH,FLASH,CODE=1C-1FFF
-! Определение сегментов в RAM. Регистровый файл находится в ячейках 0-1F,
memory mapped I/O в ячейках 20-5F, встроенное SRAM в 60-25F. -!
-! Размер стека возвратов (RSTACK) равен 32 байтам (20 hex), размер стека
данных (CSTACK) равен 96 байтам (60 hex) -!
-Z(DATA)IDATA0,UDATA0,RSTACK+20,IDATA1,UDATA1,ECSTR,CSTACK+60=60-25F
-! Выбор урезанной версии printf, чтобы уменьшить размер кода, подключаемого
из библиотек. См. секцию конфигурирования в руководстве IAR C-compiler
Users Guide, касающейся использования printf/sprintf. -!
-e_small_write=_formatted_write
-e_small_write_P=_formatted_write_P
-! Запрет поддержки операций с плавающей точкой в scanf, чтобы уменьшить размер
кода, подключаемого из библиотек. См. секцию конфигурирования в руководстве
IAR C-compiler Users Guide, касающейся использования scanf/sscanf -!
-e_medium_read=_formatted_read
-e_medium_read_P=_formatted_read_P
-! Подавления warning-а, который не относится к данному типу процессора -!
-w29
-! Загрузка C-библиотеки для модели памяти small, опция процессора option_V1 -!
cl1s
Пример показывает использование AT90S8515 с 8 килобайтами памяти FLASH, 512 байтами internal RAM, 32 килобайтами внешней оперативной памяти (external RAM) и memory mapped I/O. Стек возвратов RSTACK (Return Stack) размещен в external RAM. Для памяти кода только сегмент INTVEC указано размещать по определенному адресу. Все другие сегменты займут последующие адреса в том порядке, в каком они появляются в файле команд линкера. В RAM адреса 60-FF (HEX) зарезервированы для переменных tiny. Остальная часть внутренней памяти (internal RAM) зарезервирована под сегменты ECSTR и CSTACK.
-! Командный файл XLINK для AT90S8515. 512 байт внутреннего пространства
данных, 32 килобайта external SRAM, memory mapped I/O и 8 килобайт
адресного пространства под код программы. -!
-! Здесь задан тип процессора (AVR) -!
-ca90
-! Определение сегмента для сброса и векторов прерываний -!
-Z(CODE)INTVEC=0-1B
-! Определение сегментов в памяти flash -!
-Z(CODE)RCODE,CDATA0,CDATA1,CCSTR,SWITCH,FLASH,CODE=1C-1FFF
-! Определение сегментов в RAM. Встроенное SRAM занимает адресное
пространство 60-25F. Регистровый файл находится в адресах 0-1F
и memory mapped I/O в адресах 20-5F. -!
-! Сегменты IDATA0 и UDATA0 содержать переменные tiny, так что эти
сегменты должны находиться в пределах доступа tiny-указателя
(8 бит под адрес). -!
-Z(DATA)IDATA0,UDATA0=60-FF
-! Стек данных в internal memory, размер 256 байт (100 в hex) -!
-Z(DATA)ECSTR,CSTACK+100=100-25F
-! Начальная область 32 килобайт external SRAM используется для
переменных near. Размер стека возвратов 64 байта (40 в hex),
он находится в external RAM. Сначала говорим коду CSTARTUP,
что RSTACK размещен в External RAM. -!
-e?RSTACK_IN_EXTERNAL_RAM=?C_STARTUP
-Z(DATA)IDATA1,UDATA1,RSTACK+40=260-7FFF
-! Используется External memory mapped IO -!
-Z(DATA)NO_INIT=8000-FFFF
-! Выбор урезанной версии printf, чтобы уменьшить размер кода, подключаемого
из библиотек. См. секцию конфигурирования в руководстве IAR C-compiler
Users Guide, касающейся использования printf/sprintf. -!
-e_small_write=_formatted_write
-e_small_write_P=_formatted_write_P
-! Запрет поддержки операций с плавающей точкой в scanf, чтобы уменьшить размер
кода, подключаемого из библиотек. См. секцию конфигурирования в руководстве
IAR C-compiler Users Guide, касающейся использования scanf/sscanf -!
-e_medium_read=_formatted_read
-e_medium_read_P=_formatted_read_P
-! Подавления warning-а, который не относится к данному типу процессора -!
-w29
-! Загрузка C-библиотеки для модели памяти small, опция процессора option_V1 -!
cl1s
Дополнительную информацию можно найти в следующей литературе:
• IAR C-Compiler Users Guide. • IAR Assembler Users Guide, секция XLINK. • AVR Microcontroller data book, май 1997.