Если ничего нет, но очень хочется… 🙂
Не Keil’ом единым…
Есть такая компания, называется она IAR Systems. Делает много вещей, в том числе и среды разработки и компиляторы для различных архитектур, список которых довольно обширен. Также в числе продуктов компании есть отладчики, наборы разработчиков и т.д. Более подробно со всем этим разнообразием можно ознакомиться на их родном сайте iar.com
Нас же сейчас интересует среда для разработки приложений для архитектуры ARM, в частности Cortex-M3. Есть в их ассортименте и такой продукт и называется он EWARM, что является сокращением от Embedded Workbench for ARM, что в свою очередь, в моем вольном переводе на великий и могучий, звучит примерно как «Среда разработки для встроенных систем на архитектуре ARM», впрочем, за точность я не ручаюсь…
Данная среда поддерживает большое количество микропроцессоров и микроконтроллеров построенных на базе архитектуры ARM разных версий. Полный список можно посмотреть на их сайте Т.к. это серьезная среда разработки, то она поддерживает различные отладочные интерфейсы и средства сопряжения как производства самой IAR так и сторонних компаний, имеет встроенный отладчик, симулятор и т.д.
Но по причине отсутствия у меня какого либо девайса для внутрисхемной отладки рассказать я про все это не могу. А пользоваться симулятором как-то в голову даже не приходило. Я по старинке, пишу, заливаю в контроллер и смотрю что происходит. (Зато их есть у меня. И я вам скоро выдам пример того, какой это рулез. прим. DI HALT)
Есть мнение, что компилятор С/С++ у IAR один из самых лучших, но за это я не ручаюсь, хотя кое какие мои сравнения с Keil uVision v3 показали его превосходство.
В общем, это мощнейшая полноценная среда для разработчика. Кому интересно, изучайте описания на официальном сайте Есть ли версия для линукса я на сайте нигде не углядел, поэтому точно не скажу. (Боюсь, что как всегда 😉 Впрочем, там есть могучий и универсальный GCC и обязательно есть поддержка ARM. Так что если есть желающие показать старт проекта под линухом — ждем с распростертыми обьятьями. Пишите на [email protected] прим. DI HALT)
На момент написания данной статьи доступна версия 6.10 (я же буду рассказывать на примере версии 5.4).
Сколько стоит данное чудо я, к сожалению, на их официальном сайте найти так и не смог, а лазить по сайтам дилеров как-то недосуг… На наше счастье, данный продукт доступен в демо режиме для ознакомления. (Я тоже полазил, не нашел. Кейл стоит около 3 килобаксов. IAR, думаю, в тех же пределах. Вполне подьемно для коммерческого применения прим. DI HALT)
И здесь есть 2 варианта
Обе версии, кроме того имеют следующие ограничения:
Ну и как всегда есть вариант найти на просторах сети дистрибутив включающий все, что нужно для снятия этих ограничений.
Итак, выбираем для себя вариант, который подойдет больше всего, скачиваем и устанавливаем. Здесь вопросов возникнуть не должно, все тривиально.
После установки можно приступать к созданию проекта. Запускаем IAR Embedded Workbench и видим следующее окно:
Лирическое отступление.
Если кто-то, как я, привык для копирования/вставки использовать сочетание клавиш Ctr+Insert/Shift+Insert, то его ждет засада! EWARM по умолчанию понимает только Ctrl+C/Ctrl+V и при нажатии Ctr+Insert или Shift+Insert только меняет режим вставки/перезаписи текста. Почти месяц меня это жутко бесило, пока однажды мне не стукнуло что-то в голову и не пришла мысль порыться в настройках… Оказалось, что это легко лечится путем назначения сочетаний клавиш командам! Делается это во вкладке меню Tools->Options, далее Keybindings.
Выбираем в меню:
Project->Create New Project |
Project->Create New Project
Открывается окошко создания нового проекта.
На данном этапе можно выбрать из шаблонов, что именно мы хотим создать, но выбор там не велик, а все шаблоны содержат пустые заготовки файлов с нужным расширением и заголовками. Поэтому не ломаем голову а выбираем
и жмем кнопочку ОК
Появится диалог выбора имени проекта и указания, куда его сохранить. Называем проект милым вашему сердцу названием и сохраняем в укромном месте. Я же назвал его LEDTest, что какбы намекает… В итоге получаем следующую картину:
Создался новый проект содержащий только один файл main.c который содержит только одну пустую функцию main(). А вы хотели большего? Дальше все ручками.
На данном этапе желательно нажать на кнопку с изображением трех дискеток или через меню
EWARM попросит ввести имя WorkSpace (воркспейс может содержать множество проектов) и не мудрствуя лукаво я назвал его также LEDTest.
В отличие от Keil’a EWARM не попросил указать целевое устройство и все остальное, поэтому лезем в свойства проекта и начинаем его настраивать.
По аналогии с Microsoft Visual Studio EWARM позволяет создавать произвольное число конфигураций и по умолчанию создает в проекте 2 конфигурации Debug и Release, что подразумевает 2 набора параметров, одни для компиляции кода содержащего отладочную информацию и другой для кода без нее. Выбираем наиболее подходящую для себя.
Я, например, сразу выставляю Release и настраиваю только ее, но это дело вкуса и наличия или отсутствия у вас средств отладки.
Итак, идем в меню
Либо нажимаем Alt+F7, либо тыкаем правой кнопкой мыши на корне дерева слева и выбираем в меню Options. Появляется окно настроек проекта.
Первая категория – General Options
Здесь желательно выбрать ядро для которого нужно откомпилировать код или указать конкретное устройство. По умолчанию указано ядро ARM7TDMI. Переключаем радиобуттон на Device, нажимаем на кнопку справа от поля ввода и в списке выбираем
, где Y соответствует семейству имеющегося у вас микроконтроллера. Я выберу ST STM32F10xxE.
Далее по вкладкам и категориям буду пробегаться кратко и без картинок т.к. вкладок много и не все они важны для нас на данном этапе. На существенных остановлюсь подробно.
Output (вывод)
Здесь указываем что мы хотим получить навыходе, исполняемую программу или библиотеку. Оставляем без изменения – Executable. Также здесь можно прописать пути куда ложить откомпилированную программу/библиотеку, объектные файлы и файлы листингов. Меняем, если душа того просит.
Library Configuration (конфигурация runtime библиотеки языка С). Это тема отдельной телепередачи 🙂 но сейчас можно смело поставить None и пройти дальше.
Library options (опции стандартной библиотеки языка С)
Здесь настраивается работа функций printf и scanf. Вернее поддержка различных ключей строки форматирования. Ниже кратко расписано какая опция что поддерживает, а более подробно можно прочитать в документации идущей в комплекте с EWARM. Поддержка более сложных ключей форматирования увеличивает размер кода т.к. обработчики строки форматирования разные по сложности реализации. В данном проекте нам это не важно т.к. данными функциями мы пользоваться не будем. А в последущием я освещу данный вопрос подробнее.
MISRA-C: 2004 и MISRA-C: 1998. Настройки расширений MISRA-C. Что это такое, я честно не знаю. 🙂
C/C++ Compiler (настройки компилятора С/С++)
Здесь настраивается поддержка расширений языков С/С++, режимы оптимизации компилятора, генерация отладочной информации, пути к инклудам и т.д. Здесь пока можно ничего не трогать.
Assembler
Соответственно настройки языка ассемблера. Здесь пока можно ничего не трогать.
Output Converter (конвертация вывода)
Вот это нам нужно. Дело в том, что по умолчанию EWARM генерирует исполняемый файл в формате ELF, что какбы намекает, что Unix и прочие линуксы IAR’у не чужды.
Но нам то они ни к чему, поэтому смело тыкаем галку Generate additional output (генерировать дополнительный выходной файл) и в списке Output format (формат выходного файла) выбираем подходящий для себя, вернее для используемого вами программатора, формат.
Выбор особо не велик и реально для большинства будет состоять из двух вариантов: Intel extended, в простонародье именуемый HEX или binary. Я лично пользуюсь вариантом binary. Здесь же, если того требуют ваши религиозные убеждения, можно задать имя выходного файла отличающееся от дефолтного.
Custom build (пользовательская сборка)
Здесь можно задать дополнительные утилиты и их параметры которые будут использоваться при сборке проекта, но нам это ни к чему — пропускаем.
Build Actions (действия при сборке)
Здесь можно указать команды которые нужно выполнить перед сборкой или после. Поступаем аналогично предыдущему пункту.
Категория Linker (линковщик)
Вкладка Config (конфигурация). Здесь содержится ссылка на используемый файл конфигурации линковщика. Это очень важный файл т.к. именно в нем прописана конфигурация нашего микропроцессора в части памяти (ее наличия или отсутствия, адресации и размера), размещения таблицы векторов прерываний, размеры стека и кучи. По умолчанию проставлена ссылка на файл конфигурации идущий в комплекте с EWARM’ом и едином для всех устройств на базе ядра Cortex, что не есть хорошо, т.к. устройства все разные, объемы флеша и ОЗУ у них разные и т.д. К счастью, есть возможность отредактировать этот файл самостоятельно, что дает широчайший простор творчеству, либо с использованием кнопки Edit… находящейся здесь же.
Самостоятельная конфигурация файла настроек линковщика, занятие бесспорно увлекательное и плодотворное, но оно выходит далеко за рамки данной статьи т.к. только об этом можно написать не одну статью. Подробно все описано в руководстве пользователя, идущем в комплекте с EWARM. Скажу лишь, что там можно создавать сегменты памяти, указывать их тип, размер, размещение и еще много чего. Иногда это очень нужно, но это уже в более серьезных проектах.
Поэтому ограничимся нажатием кнопочки Edit… Правда перед этим нужно решить один концептуальный вопрос.
Дело в том, что как я уже сказал выше, данный файл является заготовкой для всей архитектуры Cortex, поэтому если вы его измените, а потом захотите создать проект для другого контроллера, того-же NXP LPC17XX, то его опять придется редактировать уже под этот процессор. Тут есть 3 варианта решения:
Итак, выбираем вариант себе по душе (я лично пользуюсь 3-им вариантом а путь прописываю так:
$PROJ_DIR$\stm32f103re.icf |
$PROJ_DIR$\stm32f103re.icf
Переменная $PROJ_DIR$ разворачивается в путь до папки с проектом автоматически, т.е. путь получается относительным. Таким образом можно папку с проектами копировать потом куда угодно и файл не «потеряется» в отличие от использования жесткого пути), выбираем свой файл отредактировав путь или нажав кнопку выбора файла (кнопка с «…» справа от едита) и нажимаем кнопку Edit…
В появившемся окошке в первой вкладке Vector Table задаем адрес таблицы векторов прерываний. Что это такое, для тех кто не в курсе, я не буду раскрывать. (Я тоже не скажу :), т.к. все уже сказано в разделе про AVR. Тут все точно также, только векторов больше. прим DI HALT)
Адрес может быть либо 0х00000000 либо 0х08000000. Я предпочитаю ставить 0х08000000 т.к. он указывает на начало внутренней флеш памяти, а адрес 0х00000000 может мэпиться на флешку а может и нет, в зависимости от состояния входов BOOT в момент инициализации контроллера, но это нужно уже курить даташит на устройство.
Вкладка Memory Regions (регионы памяти).
Здесь задается 2 важных для работы контроллера вида памяти ROM (ПЗУ) и RAM (ОЗУ) вернее их адреса начала и окончания. ROM — это наша внутренняя флеш память. Начинается она с адреса 0х08000000, это заложено в архитектуре контроллера. А вот заканчивается у каждого по разному. Зависит от объема который есть в вашем контроллере.
У меня ее 512Кб, а у вас может быть 32, 64, 128, 256. Т.е. адрес окончания этой области памяти вычисляете сами. Для меня он будет равен 0x0807FFFF (адрес начала 0x08000000 + размер флеша (512*1024) – 1 в шестнадцатеричном формате). Для вас это может быть 0x08007FFF, 0x0800FFFF, 0x0801FFFF и т.д. Желательно указывать точный размер чтобы полученная прошивка не превысила этот размер, а так линковщик ругнется в случае чего. Но нам это не грозит пока. Аналогично заполняем поля для RAM, зная из чтения даташита, что она начинается с адреса 0x20000000 и посчитав где она закончится.
Если ошибетесь в этих адресах, особенно начальных, например нолик пропустите или лишний напишите, то программа просто не будет работать.
Вкладка Stack/Heap Sizes (размеры стека и кучи)
Параметры говорящие сами за себя.
Стек нужен для передачи параметров функциям, сохранения точек возврата из них и т.д. Сильно большим его делать не имеет смысла т.к. зря будет расходоваться ОЗУ, а если сделать сильно маленьким, то может не хватить (особенно если будет использоваться много вложенных функций). Поставим его равным 0x200 т.е. 512 байт. В нашем проекте этого более чем достаточно.
Куча – это часть ОЗУ выделенная для функций работы с памятью языка С/С++ таких как malloc, оператор new и т.д. В данном проекте мы их использовать не планируем, поэтому ставим 0.
Все, нажимаем кнопочку Save.
В остальных вкладках категории Linker настраиваются подключаемые внешние библиотеки, пути к ним, настройка имени выходного файла, настройки генерации листингов, расчета контрольных сумм и т.д. Нам в данном проекте ничего из этого не понадобиться, а объяснять все слишком долго. Будут конкретные вопросы — спрашивайте в комментах.
Категория Debuger (отладчик)
Здесь настраиваются аппаратные средства внутрисхемной отладки либо отладка в симуляторе. Как я уже говорил, аппаратных средств у меня нет, а симулятором я не пользуюсь. Поэтому рассказать тут особо ничего не могу.
С облегчением жмем кнопку Ок справа-внизу окошка, и применяем выбранные параметры.
Теперь можно смело нажать кнопку F7 или в меню
и откомпилировать наш проект.
В папочке которую вы указали для выходных файлов программы (если ничего не меняли, то это будет, в зависимости от выбранной конфигурации, папка Debug/exe либо Release/exe в папке с проектом) увидим 2 файла. Один с раширением .out и второй .bin или .hex, в зависимости от того, что вы указали в качестве дополнительного выходного файла.
Все, наша первая программа готова! Можно прошивать ее в контроллер и она заработает! Не верите? А вы попробуйте.
На этом позвольте закончить мою первую статью т.к. она и так получилась не маленькой. А к написанию более функционально насыщенной программы мы перейдем на следующем нашем шаге.
PS:
Хочу еще пару слов сказать о прошивке контроллера. Как я написал в эпиграфе, если ничего нет, но очень хочется… Если у вас нет аппаратного прошивальщика и/или отладчика, то это не большая проблема. Дело в том, что прошить контроллер STM32F можно с использованием обычного интерфейса USART, в простонародье это называется через COM порт. В идеале, если на плате с микроконтроллером распаян преобразователь уровней USART в TTL и заведен на порт USART1 контроллера (ножки PA.8 PA.9). Если нет, то тоже не большая беда. Можно немного распотрошить любой кабель-переходник USBCOM (в крайнем случае покупается в магазине), там внутри стоит микросхема с TTL уровнями, и пользоваться им подключаясь напрямую к ножкам контроллера. Про выставление уровней BOOT0/1 и как входить в режим бутлоадера можно узнать из даташита. А прошивать можно программой Flash Loader Demo производства самой ST Microelectronics. Я пользуюсь именно ей. Правда почему-то найти ее на сайте ST невозможно, поэтому прикладываю ее к своей статье, спасибо за нее нашим китайским братьям!
Многофункциональная среда разработки приложений на языках C, C++ и ассемблере для целого ряда микроконтроллеров от различных производителей.
Основные преимущества пакета – дружественный пользовательский интерфейс и непревзойденная оптимизация генерируемого кода. Кроме этого реализована поддержка различных операционных систем реального времени и JTAG -адаптеров сторонних компаний.
В настоящее время IAR Embedded Workbench поддерживает работу с 8-, 16-, 32-разрядными микроконтроллерами от Atmel, ARM, NEC, Infineon, Analog Devices, Cypress, Microchip Technologies, Micronas, Dallas Semiconductor/Maxim, Ember, Luminary, NXP, OKI, Samsung, National Semiconductor, Texas Instruments, STMicroelectronics, Freescale, TI/Chipcon, Silicon Labs и Renesas. Для каждой платформы существует своя среда разработки, в частности ARM микроконтроллерам соответствует версия пакета IAR Embedded Workbench for ARM.
Программная среда включает в себя:
1. C/C++ компилятор – один из самых эффективных в своем роде. В нем также присутствует полная поддержка ANSI C.
2. Транслятор ассемблера, включающий в себя макроассемблер для программ реального времени и препроцессор для C/C++компилятора.
3. Компоновщик, поддерживающий более тридцати различных выходных форматов для совместного использования с внутрисхемными эмуляторами.
4. Текстовый редактор, настроенный на синтаксис языка Си и имеющий удобный пользовательский интерфейс, автоматическое выделение ошибок программного кода, настраиваемую инструментальную панель, подсветку блоков, а также удобную навигацию по именам подпрограмм, макросов и переменных.
5. Симулятор и отладчик в кодах Си и ассемблера. Отладчик позволяет просматривать области EEPROM, DATA, CODE, а также регистры ввода/вывода, устанавливать точки останова и аппаратные флаги, обрабатывать прерывания с предсказанием. Кроме этого предусмотрен контроль стека и любых локальных переменных, режим пошагового выполнения программы. Тип отладчика и его настройки устанавливаются в свойствах проекта. Если отладчик отсутствует, то на помощь приходит симулятор, который, однако, не имеет возможности эмулировать работу процессора.
6. Менеджер проектов, облегчающий контроль и управление рабочими модулями.
7. Дополнительные утилиты для работы с оптимизированной CLIB/DLIB библиотекой.
Интегрированная система помощи облегчает написание программ в данной среде. Предусмотрено взаимодействие с утилитой AVR Studio. Помимо прочего в IAR Embedded Workbench существует возможность самостоятельного управления оптимизацией отдельных модулей проекта, что упрощает процесс отладки, а также позволяет ускорить работу программы или сэкономить на памяти.
IAR Embedded Workbench была разработана IAR Systems, более двадцати лет являющейся одной из ведущих компанией по созданию C/C++ компиляторов для встраиваемых микроконтроллерных устройств и систем. Ее штаб-квартира находится в старинном городе Уппсала (Швеция). В настоящее время программы IAR Systems используют по всему миру более сотни тысяч разработчиков, производителей телекоммуникационного и промышленного оборудования, медицинской и компьютерной техники, среди которых такие гиганты, как Apple Computer, Cisco Systems, Motorola, Hewlett-Packard и Siemens.
IAR Embedded Workbench является коммерческим продуктом, его стоимость составляет около 3000 долларов за одну пользовательскую лицензию. Однако, в качестве дополнения к полнофункциональной версии, существует бесплатный вариант среды программирования с единственным ограничением на размер выходного кода до 4 или 8 КБ в зависимости от модели контроллера. Этот вариант подойдет для первого знакомства с программой, а также написания небольших приложений. Можно найти и взломанную версию, но для ее нормальной работы придется отключать выход в интернет.
Язык интерфейса IAR Embedded Workbench – английский.
Рассматриваемая среда работает под управлением только операционной системы Microsoft Windows версий 95, 98, NT, 2000, XP, Vista, 7 (не имеет значения 32- или 64-битных).
Распространение программы: платная. Есть бесплатная версия с ограничениями на размер кода в зависимости от МК
Официальный сайт IAR Embedded Workbench: http://www.iar.com
Скачать IAR Embedded Workbench
Обсуждение программы на форуме
Я начинал свое изучение AVR с книги 16. Сейчас самые используемые мной книги это 10, 11, 12. Вообще я думаю если этих книг скачать, то начинающему на 5 лет хватит.
Архив качаем отсюда.
Продолжение темы здесь.
Популярная мощная и удобная среда разработки и отладки программ для микроконтроллеров и процессоров архитектуры ARM:
Cortex-M0, M3, M4, M7, A9
Поддерживает процессоры следующих фирм:
ActiveSemi, AmbiqMicro, AnalogDevices, Atmel, Broadcom,
Cirrus, Cypress, Ember, Epson, Faraday,
Freescale, Fujitsu,Hilscher, Holtek, Infineon,
Intel, Linear Technology, Marvell, Maxim, Micronas,
Microsemi, NetSilicon, NordicSemiconductor, Nuvoton, NXP
OKI, ONSemiconductor, Renesas, Samsung, SiliconLabs,
Socle, Sonix, Spansion,ST Microelectronics, Texas Instruments,
Toshiba, Xilinx.
Что нового:
— усовершенствованный компилятор
— параллельная многопоточная комиляция!!!
— обновленные библиотеки
— устранены некоторые ошибки
— поддержка новых чипов
— поддержка double precision FPU для Cortex-M7 (начиная с v 7.40)
— поддержка PTM trace для ядер Cortex-A
— поддержка ETMv4 trace для ядер Cortex-M7
Доп. информация: Исходники библиотек распаковываются после установки лицензии
Порядок лечения — в файле ReaDme.txt
Лечение:
1 — Скачать файл с внешнего сервера MEGA-DRIVE: IAR Embedded Workbench for ARM v7.70.1
2 — Скачать KeyGen с внешнего сервера MEGA-DRIVE: IAR v7.70.1KeyGen
Так как микроконтроллеры AVR имеют Гарвардскую архитектуру, для каждого типа памяти SRAM, FLASH, EEPROM у них выделено отдельное адресное пространство. Каждая из этих типов памяти имеет собственное специальное назначение. Если данные не изменяются в течение работы программы, то они должны быть сохранены в памяти либо FLASH, либо EEPROM. В другом случае, если данные переменной часто используются и постоянно изменяются, то такая переменная должна быть сохранена в памяти SRAM. Где какие данные разместить — решает разработчик программы. Важное правило, которое следует учитывать — работа с разными типами памяти требует разных операций и способов доступа. Обычно когда на C просто определяют переменную наподобие int a, компилятор автоматически помещает её в SRAM. Но если Вы захотите, то можете разместить константы в памяти EEPROM и даже в памяти FLASH. Для памяти SRAM для размещения переменных не нужно указывать никакого специального синтаксиса, но для EEPROM и FLASH нужно использовать специальные методы для декларации переменных. Несмотря на указание const при декларации констант, компилятор все равно для их хранения использует ОЗУ (при старте программы они просто копируются из flash в RAM). Это несомненно полезно с точки зрения быстродействия кода, но для программ, активно использующих ОЗУ и/или имеющих большой объем констант (например, строковых), памяти ОЗУ может оказаться недостаточно. Обойти проблему позволяет атрибут PROGMEM и подпрограммы для работы с данными из flash. Их можно использовать, если включить заголовочный файл avr\pgmspace.h. Функции заголовка подробно описаны в C:\WinAVR-20090313\doc\avr-libc\avr-libc-user-manual\pgmspace_8h.html. Принцип работы gcc, описание проблемы подробно описаны в файле C:\WinAVR-20090313\doc\avr-libc\avr-libc-user-manual\pgmspace.html. Далее дан его почти дословный перевод. [Данные в памяти программ] Многие микроконтроллеры AVR оборудованы недостаточым количеством памяти RAM для хранения данных и констант, однако они имеют в своем распоряжении гораздо больший объем памяти программ (flash). Во flash вполне могли бы поместиться константы, что сэкономит драгоценное место в RAM. Однако микроконтроллеры AVR имеют гарвардскую архитектуру, в которой четко разделены память программ (flash) и память данных (RAM), и каждая имеет свое отдельное адресное пространство. Имеется связанная с этим некоторая проблема, чтобы сохранять данные констант во flash, и затем считывать эти данные в программе AVR. Проблема усугубляется еще тем, что язык C был разработан не для гарвардской архитектуры, а для архитектуры фон Неймана, где код и данные сосуществуют в едином, общем адресном пространстве. Поэтому любой компилятор для гарвардской архитектуры, например AVR, должен иметь разные методы для работы с разными адресными пространствами. Некоторые компиляторы C (например IAR Embedded Workbench for AVR) используют нестандартные ключевые слова, либо расширяют стандартный синтаксис. Набор инструментов WinAVR/gcc используют другой способ. Компилятор GCC имеет специальное ключевое слово __attribute__, которое используется для подсоединения различных атрибутов к функциям, определениям, переменным и типам. Это ключевое слово сопровождается спецификацией атрибута в двойных круглых скобках. В AVR GCC имеется специальный атрибут progmem. Он используется при декларации данных, и говорит компилятору поместить данные в памяти программ (flash). Библиотека AVR-Libc предоставляет простой макрос PROGMEM, который задает синтаксис GCC-атрибута progmem. Эта макрокоманда была создана для удобства конечного пользователя, как мы увидим далее. Макрос PROGMEM задан в заголовочном файле < avr/pgmspace.h >. Поскольку сложно модифицировать GCC для создания нового расширения синтаксиса C, вместо этого avr-libc имеет макросы для получения данных из flash. Они также размещены в заголовке < avr/pgmspace.h >. [О ключевом слове const] Многие пользователи полагают, что использование ключевого слова const декларирует размещение данных в памяти программ (flash). Это происходит из-за неверного понимания назначения ключевого слова const. Ключевое слово const говорит компилятору, что данные «только для чтения», и не более того. Это упрощает для компилятора некоторые преобразования, и предотвращает некорректное использование этих переменных. Например, const используется многими функциями в качестве модификатора типа параметра. Это говорит компилятору, что функция будет использовать этот параметр только для чтения, и не будет изменять содержимое параметра. Таким образом, const всего лишь указывает на метод использования данных, и совсем не говорит о том, где должны эти данные храниться. Если это слово использовать как средство определить хранение данных, то мы окажемся в проигрыше, так как это изменит его семантику в других ситуациях, например в параметре функции. [Сохранение данных в памяти программ и получение их оттуда] Предположим, у Вас есть некоторые глобальные данные: unsigned char mydata[11][10] = { {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09}, {0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13}, {0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D}, {0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27}, {0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31}, {0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B}, {0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45}, {0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F}, {0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59}, {0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63}, {0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D} }; И далее код будет получать эти данные, например так: byte = mydata[i][j]; Теперь Вы хотите сохранить данные в памяти программ (flash). Используйте макрос PROGMEM и поместите его в декларацию переменной, но перед инициализатором: #include <avr/pgmspace.h> . . . const unsigned char mydata[11][10] PROGMEM = { {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09}, {0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13}, {0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D}, {0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27}, {0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31}, {0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B}, {0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45}, {0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F}, {0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59}, {0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63}, {0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D} }; Теперь Ваши данные хранятся в памяти программ. Можно скомпилировать, слинковать, и проверить карту памяти — массив mydata будет лежать в правильной секции. Но теперь код, получающий данные не будет работать, так как начало массива все равно интерпретируется компилятором как адрес в пространстве данных. Проблема в том, что для AVR GCC несвойственно знать, что данные могут лежать в пространстве программ. Решение проблемы довольно простое. Сначала нам надо получить адрес необходимых данных. Он равен &(mydata[i][j]). После этого можно использовать макрос для чтения данных из памяти программ по этому адресу: byte = pgm_read_byte(&(mydata[i][j])); Имеются различные макросы pgm_read_* для чтения данных разного типа и размера. Все они принимают адрес, указывающий на память программ (flash), и возвращают данные, сохраненные по этому адресу. Макросы обеспечивают для этого генерацию корректного кода. [Сохранение строк в памяти программ и получение их оттуда] Предположим, у нас есть массив строк: char *string_table[] = { "String 1", "String 2", "String 3", "String 4", "String 5" }; Теперь добавляем макро PROGMEM и ключевое слово const: const char *string_table[] PROGMEM = { "String 1", "String 2", "String 3", "String 4", "String 5" }; Верно? Нет! К сожалению, атрибуты GCC затрагивают только объявление, к которому они присоединены. В этом случае мы действительно поместили переменную string_table, т. е. сам массив, в память программ, но не сами строки. Строки так и остались в памяти данных (RAM), что наверное не совсем то, то Вы хотели. Чтобы поместить строки во flash, нужно явно объявить каждую строку: const char string_1[] PROGMEM = "String 1"; const char string_2[] PROGMEM = "String 2"; const char string_3[] PROGMEM = "String 3"; const char string_4[] PROGMEM = "String 4"; const char string_5[] PROGMEM = "String 5"; И потом использовать новые символы в массиве: PGM_P string_table[] PROGMEM = { string_1, string_2, string_3, string_4, string_5 }; Теперь мы разместили массив string_table во flash, и массив string_table является массивом указателей на строки. Каждый указатель при этом указывает на строку во flash, где строка и хранится. Например, Вы хотите скопировать строку из flash в буфер RAM (например в автоматическую переменную внутри функции, расположенную в стеке). Для это нужно сделать следующее: void foo(void) { char buffer[10]; for (unsigned char i = 0; i < 5; i++) { strcpy_P(buffer, (PGM_P)pgm_read_word(&(string_table[i]))); // Display buffer on LCD. } return; } Смысл приведенного кода очевиден — получение данных из массива происходит через указатель, выбираемый как 16-битное беззнаковое целое макросом pgm_read_word. Далее строка копируется функцией strcpy_P. Имеется множество функций для манипуляции строками в памяти программ с индексом _P, работающих так же, как и обычные строковые функции. Все эти функции с индексом _P также определены в заголовке <avr/pgmspace.h>. [Предостережение] Макрос и функции, используемые для получения данных из flash, генерируют некоторый дополнительный код, который больше по объему, чем код доступа к памяти RAM. Таким образом, это создает дополнительный расход памяти программ и замедление работы кода. Этот дополнительный расход и замедление достаточно малы, поэтому выигрыш при размещении данных во flash получается значительный. Однако об этом необходимо знать, чтобы при необходимости минимизировать количество обращений к памяти внутри одной функции и/или цикла. В этом может помочь поучительный просмотр дизассемблированного кода компилятора. [Строки и константы FLASH в IAR] Среда разработки IAR Embedded Workbench for AVR также имеет специальные средства для размещения данных и констант в памяти программ. Для этого используется специальный заголовок pgmspace.h. Для манипуляции с данными из FLASH используются специальные функции с суффиксом _P: sprintf_P, strcpy_P, sscan_P и т. д. Для объявления данных во FLASH служит ключевое слово __flash. Например: #include .. //Обычный буфер в RAM: char buffer [256]; //Текст, хранящийся в памяти программ (FLASH): __flash char message[] = "Hello, world!\r\n"; //Работа с данными FLASH: sprintf_P(buffer, "%s", message); |