Winavr

Winavr

Основы работы в WinAVR

В качестве платформы для разработки конструкций на микроконтроллерах я использую пакет программ WinAVR. Почему выбор пал именно на него? Данная платформа распространяется бесплатно с открытым исходным кодом. Каждый может её улучшить и доработать по своему усмотрению (хотя смысла это делать не вижу). Генерирует достаточно оптимальный код.

Синтаксис языка с в нём максимально приближён к классическому Си, нету конструкций типа PORTB.1 = 1 как в CVAVR. Вообще у меня на компьютере установлены и WinAVR, и пресловутый CVAVR. Есть и PonyProg, и даже Algorithm Builder. �? всеми ими приходится иной раз  пользоваться , т.е. они друг друга прекрасно дополняют.

Например, когда возникла необходимость прошить AT90USB162, я сделал это при помощи CVAVR, т.к. ни PonyProg, ни USBASP_AVRDUDE_PROG не поддерживают данный кристалл. Кроме того CVAVR удобно пользоваться, если надпись на кристалле затёрта и не известен тип. Для этого, после подключения программатора, во вкладке «chip programmer» нажимается кнопка «read signature».

Этой же функцией можно воспользоваться, если есть подозрения в исправности программатора или самой микросхемы.  Algorithm Builder удобно использовать для написания программ для 8-миногих «тинек» — изучая ассемблер, изучается внутренняя архитектура контроллера. Кроме того, при расчёте некоторых величин для записи в регистры удобно смотреть по вкладкам AB, т.к.

при вводе частоты работы ядра автоматически рассчитываются, например, значения регистров для установки скорости обмена по UART, другие величины… Но я отвлёкся, разговор-то идёт про WinAVR. �?так, качаем дистрибутив отсюда и устанавливаем на своём компьютере. Я думаю пошагово объяснять установку не нужно – все, читающие эти сроки, наверняка подготовлены как пользователи ПК.

Главной программой, в которой собственно и идёт работа является Programmer Notepage. Для себя я вынес её ярлык на рабочий стол ПК. Открываем Programmer Notepage, «File» -> «New». Откроется окно нового файла. Предварительно создадим папку в которой будут храниться наши проекты. В эту папку сохраним новый файл с расширением с. Набираем собственно код.

Для примера я использовал небольшой проектик, который будет выводить на экран LCD индикатора все возможные для него символы, ведь содержимое знакогенератора адресов 0xA0 – 0xFF для различных видов HD44780-совместимых LCD индикаторов может меняться от модели к модели. �?так, набираем код. Сохраняем его как znakogenerator.c в папку Znakogenerator.

Кроме того, для работы с LCD необходимо подключить файл с набором таких функций. Берём его из своей наработанной библиотеки и копируем в эту же папку. Ну и для задания параметров самого проекта необходимо создать так называемый makefile.

В дальнейшем, после приобретения некоторого опыта данный файл можно будет копировать из других своих проектов, а я сейчас покажу как сделать его с помощью специальной программы из пакета WinAVR. Кликаем «Пуск» -> Все программы -> WinAVR -> MFile (иконка в виде кипящего чайника). Открывается окно.Кликаем «Mikefile» и начинаем вводить параметры своего проекта.

В основном там нужно будет поменять название главного файла проекта (по умолчанию «main»), мы вводим znakogenerator, выбрать тип микроконтроллера MCU type, остальное можно не трогать, все параметры, в том числе и указанные выше, возможно поменять будет потом в папке проекта.

Потом кликаем «File» -> «Save As» и сохраняем его как mikefile (по умолчанию) в папку Вашего проекта, в нашем случае папку Znakogenerator. Сохранили, теперь из Programmer Notepage открываем папку проекта и видим там четыре файла: znakogenerator.c – это основной файл проекта, lcd.c, lcd.

h – файл функций работы с LCD и заголовочный файл к нему (мы их добавили из своей библиотеки) и makefile  проекта, который мы с вами создавали. Откроем его.

Всё, что написано после символа # — это комменты, они нас не интересуют, хотя, если владеете английским можно почитать. Смотрим сверху вниз. Я буду пояснять только те строки, которые необходимы, остальные можно оставить по умолчанию. MCU = atmega88 – строка где мы выбираем тип кристалла. F_CPU = 1000000 – частота работы ядра, которую мы задаём фьюзами.

TARGET = znakogenerator – строка, задающая имя главного файла проекта (того, где есть функция main), имя указывается без расширения С. SRC = $(TARGET).c – строка, указующая на источники Си-кода, под ней  добавлена строка SRC += lcd.c – этим мы подключаем к проекту файл lcd.c.

Если подключаются ещё какие-то файлы, то они так же записываются как указано выше новой строкой под существующими. Листаем вниз, до опций программатора Здесь в строке AVRDUDE_PROGRAMMER = stk500 можно выбрать любой тип программатора, который есть в выпадающем списке программы MFile. Ниже строка выбора порта связи с программатором AVRDUDE_PORT = com1.

Список портов также указан в выпадающем списке MFile. С программаторами есть небольшой ньюанс. Дело в том, что в выпадающем списке программаторов нет USBasp, а он достаточно распространён среди радиолюбителей. Ничего страшного – пропишем его вручную. Вот так: AVRDUDE_PROGRAMMER = usbasp и укажем порт: AVRDUDE_PORT = usb.

Всё, сохраним изменения, нажатием на соответствующую кнопочку. Теперь проект нужно откомпилировать и прошить в кристалл. Для этого соберём схему из элементов микроконтроллерного конструктора и подключим её к программатору USBasp, который хорошо описан здесь.

В Programmer Notepage кликаем «Tools» -> «Make Clean» — это очистит папку от предыдущих результатов компиляции. После этого «Tools» -> «Make All» — это откомпилирует проект, и, если не будет ошибок, то вылезет такое окно.

После успешной компиляции в папке проекта появиться куча файлов, о них я сейчас рассказывать не буду – можно посмотреть самим. Потом прошиваем кристалл: «Tools» -> «Program». Если всё соединено правильно, результат будет таким,

а на экране LCD Вы уведите раз в полсекунды меняющиеся символы знакогенератора и их порядковый номер.

Теперь, создавая свой проект, можно не выходя после очередной компиляции в USBASP_AVRDUDE_PROG, Pony Prog или другую программу,  зашивать кристалл и видеть результаты изменения исходного кода.

Фьюзы предварительно нужно зашить любой из вышеуказанных программ, в зависимости от используемого программатора. Следует также отметить, что WinAVR замечательно стыкуется с AVR studio, но об этом позже.

Удачи, друзья!

Запись опубликована в рубрике Разное с метками LCD, WinAVR. Добавьте в закладки постоянную ссылку.

Источник: http://www.embed.com.ua/raznoe/osnovyi-rabotyi-v-winavr/

WinAVR и AVR Studio – справочное руководство

{nomultithumb}По договоренности с редакцией журнала Радиолюбитель публикую ввсе главы из своей полунаписанной ненапечатанной книги.

Задумывалась эта книга как справочное руководство по , и большая ее часть состояла из моих собственных переводов оригинальной документации , однако потом я пополнил ее кратким введением в язык Си, описанием основ работы с , затем добавил описание различных вспомогательных утилит и, таким образом, получил винегрет, который все издательства отказались печатать.Ну а переделывать все мне было лень…

{ads2}В итоге все написанное публиковалось в течение 2010 и 2011 годов в журнале, а теперь журнальные статьи в виде PDF-файлов я размещаю здесь для всех желающих.

Приношу свои извинения за несколько “рваный” стиль изложения и отсутствие многих полезных вещей, например, примеров программ и т.п. – увы, это хотя и было задумано, так и не было реализовано.

{ads1}

Вложения:ФайлОписаниеРазмер файла:

AVR_01-2010.pdf Предисловие, Основы языка Си (начало) 314 Кб
AVR_02-2010.pdf Основы Си (продолжение) 299 Кб
AVR_03-2010.pdf Основы Си (продолжение) 314 Кб
AVR_04-2010.pdf WinAVR + AVR Studio (Установка, описание интерфейса) 2021 Кб
AVR_05-2010.pdf AVR Studio (описание интерфейса – продолжение) 1088 Кб
AVR_06-2010.pdf AVR Studio (работа с проектом) 1347 Кб
AVR_07-2010.pdf AVR Studio (отладка) 981 Кб
AVR_08-2010.pdf Обзор дополнительных средств (утилиты, программаторы, отладчики – кратко) 1474 Кб
AVR_09-2010.pdf AVR-GCC (особенности, файлы, параметры командной строки) 328 Кб
AVR_10-2010.pdf AVR-LIBC (alloca.h, assert.h, ctype.h, errno.h, inttypes.h, math.h, setjmp.h, stdint.h) 338 Кб
AVR_11-2010.pdf AVR-LIBC (stdio.h) 385 Кб
AVR_12_2010.pdf AVR-LIBC (stdlib.h, string.h) 328 Кб
AVR_01_2011.pdf AVR-LIBC (boot.h, eeprom.h, fuse.h, interrupt.h, pgmspace.h) 301 Кб
AVR_02_2011.pdf AVR-LIBC (power.h, sfr_defs.h, sleep.h, version.h, atomic.h, crc16.h, wdt.h, delay.h, delay_basic.h, parity.h, setbaud.h) 272 Кб
AVR_03_2011.pdf Распределение памяти в AVR-GCC 326 Кб
AVR_04_2011.pdf Ассемблерные модули и вставки 188 Кб
AVR_05_2011.pdf Ассемблерные модули и вставки (продолжение) 247 Кб

Обсудить на форуме (19 комментариев).

Источник: https://simple-devices.ru/articles/7-soft/12-winavr-avr-studio

WinAVR

Источник: http://cxema.my1.ru/load/winavr/1-1-0-100

Среда разработки WinAVR – программирование на МК

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

Несмотря на универсальность языка Си, его синтаксис во многом зависит от типа применяемого компилятора. Различия между версиями компиляторов существуют и подчас они значительные. Главное, не ошибиться первоначально, чтобы потом не пришлось переучиваться. Сделать осознанный выбор помогает приводимая далее «информация к размышлению».

Компиляторы 8-битных MK представляют собой узкоспециализированные компьютерные программы.

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

 К сожалению, их свободно распространяемые демо-версии имеют урезанные возможности и на перспективу для широкого применения не годятся.

На другом полюсе «обитают» бесплатные Си-компиляторы, использование которых не нарушает ничьих авторских прав.

Чтобы выбрать один из них, надо вспомнить про AVR-контроллеры фирмы Atmel, которые в настоящее время имеют большую популярность среди электронщиков.

Для их детального изучения предлагается бесплатный пакет программ WinAVR [6-1] (Рис. 6.2), в состав которого входит свободно распространяемый компилятор AVR-GCC.

Рис. 6.2. Эмблема (логотип) WinAVR:

AVR-GCC является неотъемлемой частью сообщества свободных компиляторов GCC (GNU Compiler Collection), поддерживающих операционные системы MicrosoftWindows, Linux, языки Си, С++, Ada, Fortran, Java [6-2].

В пакет WinAVR входит отдельная версия GCC-компилятора под названием AVR-GCC. Она специально «заточена» под ядро AVR фирмы Atmel, платформу Microsoft Windows и процедуры Си, С++ стандартов ANSI, ISO, C99.

6.2.1.               Философия свободных программ

Пакет WinAVR его разработчики называют «сюитой». Создан он был в начале 2000-х годов интернациональным коллективом профессиональных программистов. Координатором проекта является EricB.Weddington.

В штате добровольных помощников, которым выражается благодарность в справке помощи WinAVR, встречаются программисты из разных стран мира, в том числе и со славянскими фамилиями, в частности, Denis Chertykov, Anatoly Sokolov, DmitryXmelkov.

По функциональным возможностям WinAVR находится на одном уровне с аналогичными коммерческими продуктами (Табл. 6.1). Не секрет, что в Интернете к ним можно подобрать «ключики», «лекарства», «таблетки». Но зачем желомиться в открытую дверь, если можно легально дружить с законом, используя WinAVR?

Таблица 6.1. Перечень коммерческих Си-компиляторов для AVR-контроллеров

ИНСТАЛЛЯЦИЯ И КОНФИГУРАЦИЯ WINAVR

ВВЕДЕНИЕ

WinAVR представляет собой набор инструментальных средств для работы с микроконтроллерами семейства AVR фирмы ATMEL.

В него вошли следующие компоненты: компилятор языка C avr-gcc, библиотека компилятора avr-libs, ассемблер avr-as, интерфейс программатора avrdude, интерфейс JTAG ICE avarice, дебуггер avr-gdb, редактор programmers notepad, и еще много полезных вещей. Весь этот набор собран в один инсталляционный пакет и предназначен для установки на платформу Windows.

Текущая версия WinAVR включает в себя компилятор avr-gcc версии 3.3 и обозначается (например) как 20030424 – что представляет собой дату выхода. Весь этот набор распространяется свободно (производители поддерживают GNU General Public License).

Всю последнюю информацию по WinAVR, которую лучше почитать до скачивания инсталляционного пакета, можно найти на сайте http://winavr.sourceforge.net. Для скачивания самой WinAVR идти сюда: http://sourceforge.net/projects/winavr.

Только вот объем для скачивания довольно большой – от 12 до 18 мегабайт в зависимости от версии.

ИНСТАЛЛЯЦИЯ WINAVR

Инсталляционный пакет WinAVR представляет собой один exe файл, который необходимо запустить, дабы установить WinAVR. Вначале будет предложено ознакомиться с GNU GPL лицензией, потом следует выбрать место установки WinAVR и нажать “install”. После инсталляции будет предложено ознакомиться с файлом README.txt. Советую почитать его, там много полезной информации.

MAKEFILE

Как может показаться, компилятор avr-gcc очень неудобен тем, что запускается из командной строки без графического интерфейса пользователя (GUI). Тем не менее, этот компилятор может работать с разными программами, имеющими GUI, и легко под это дело конфигурироваться.

Читайте также:  Блок питания для домашней лаборатории

Этому способствует то, что avr-gcc использует для своей работы makefile. Makefile сообщает компилятору, какие команды запускать, какие файлы компилировать и линковать, какой выходной код генерировать, и т. д. Makefile обрабатывается программой make. Как один из способов запуска компилятора в командной строке набирается следующее:

d:mydirmyproj1>make

При этом предпологается, что makefile и компилируемый файл (для примера proj1.c) находятся в директории d:mydirmyproj1.

Следующая важная вещь, которую надо знать, это то, что makefile имеет несколько различных команд, выполнение которых зависит от содержимого makefile. Для использования определенной командыкомандная строка должна выглядеть следующим образом:

d:mydirmyproj1>make

Компилятор языка Си Фирма-разработчик Страна Интернет-адрес на 07.01.2011 Ограничение демо-версии
C-AVR SPJ Embedded Technologies Индия http://www.spjsystems.com/cavrd.htm Листинг не более 120 строк
CodeVision HP InfoTech Румыния http://www.hpinfotech.ro/html/cvavr.htm Прошивка не более 3 Кбайт
CrossWorks IAR Rowley Associates Англия http://www.rowley.co.uk/avr/index.htm http://www.iar.com/ 30 дней работы
IAR Systems Швеция 30 дней работы
lCCAVR ImageCraft США http://www.imagecraft.com/ 45 дней работы

Работа с бесплатным компилятором экономит деньги и обеспечивает лицензнную чистоту конечного программного продукта. Достаточно широко используют WinAVR и при обучении студентов, например, в Государственном университете Гранд Вэлли (г.Аллендейл, Мичиган, США) [6-3].

Версии WinAVR обновляются примерно два-три раза в год, причём наблюдается их преемственность «снизу-вверх». Первый релиз был выпущен в 2002 году (WinAVR-20021111), последний из известных — в 2010 году (WinAVR-20100110). Вереница из восьми цифр в конце названия обозначает дату выпуска версии по образцу «год-месяц-число», т.е. 20100110 — это 10 января 2010 г.

Осторожный читатель вправе заметить, что «бесплатный сыр бывает только в мышеловке». Рассеять сомнения поможет теоретическая подкованность.

Всё программное обеспечение делится на две большие группы: бесплатное (freeware, demo unlimited, no time limit) и коммерческое (shareware, commercial). Первая группа, по определению, не требует финансовых затрат и может использоваться сколь угодно долго во времени.

Вторая — предполагает короткий ознакомительный период, а затем необходимость заплатить деньги или отказаться от продукта.

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

Например, реклама потенциальных возможностей программиста, портфолио при поиске работы, юношеское самоутверждение, спортивный азарт под девизом: «И я умею не хуже!», организация клубов по интересам для коллег из разных стран, размещение в Интернете программ, к которым остыл интерес, наконец, природный альтруизм или просто широкий жест, чтобы почувствовать себя хоть один раз настоящим «добрым самаритянином».

WinAVR принадлежит к особому классу свободных программ под названием «free software». Следует отличать свободное (Open Source) и бесплатное (freeware) программное обеспечение. Первое из них можно без ограничений использовать, распространять и улучшать, а второе — только использовать и распространять.

Авторы WinAVR исповедуют принципы GNU. Аббревиатура GNU является рекурсивным акронимом фразы «GNU’s Not Unix», что в переводе с английского означает «GNU — это не Unix», и так бесконечное число раз. Начало этому движению было положено в 1983-1984 гг.

, когда дипломированный программист Ричард Столлман (Richard Stallman) начал работу над оригинальной Unix-подобной операционной системой, состоящей из свободных проектов.

Первой программой под GNU стал текстовый редактор «Emacs», созданный самим Столлманом [6-4].

Поклонники GNU придерживаются базового принципа свободного софта, что означает право пользователя свободно запускать, копировать, распространять, изучать, изменять и улучшать программы. В английском языке слово «free» переводится двояко — «бесплатный» и «свободный». В системе GNU используется второе понятие, которое имеет четыре степени свободы:

•                 «свобода-0» — возможность запускать программу в любых целях;

•                 «свобода-1» — возможность адаптировать программу под свои потребности;

•                 «свобода-2» — возможность свободно распространять копии программы;

•                 «свобода-3» — возможность улучшать программу и публиковать свои улучшения где-либо без уведомления кого-либо.

Необходимым условием осуществления «свободы-1» и «свободы-3» является доступ к исходным текстам листингов программы.

При выполнении «свободы-2» пользователь вправе взимать плату за копирование файлов (и только!), хотя может распространять их бесплатно.

Хорошим тоном при наличии «свободы-3» является упоминание в титрах программы предыстории всех изменений и выражение благодарности участникам и разработчикам проекта.

Программа считается полностью свободной от ограничений при выполнении всех четырёх степеней свободы.

Знак «копирайта» , предполагающий коммерческую защиту авторского права «copyright protection», заменяется «копилефтом», по-английски «protection via copyleft». Этот термин ввёл в обращение в 1985 г. Р.Столлман.

Единственным требованием «копилефта» является запрет на внесение любых ограничений на свободу программы.

Если внимательно проанализировать философию GNU, то её основная идея заключается в коллективном накоплении банка программ и алгоритмов, которым мог бы воспользоваться любой желающий. У программистов друг перед другом не должно быть глобальных секретов, ведь их основной труд оплачивают те, кто не умеет составлять программы.

Сторонники свободного программного обеспечения стараются подобрать бесплатные аналоги для многих повседневных программ, и это им вполне удаётся (Табл. 6.2).

С изложенной теорией можно соглашаться или спорить, но она реально существует и поддерживается организацией «Free Software Foundation, Inc.» [6-5].

Более того, по мере приобщения к Интернету программистов из развивающихся стран мира, наблюдается тенденция к увеличению числа приверженцев «Ореп Source» и «freeware».

Таблица 6.2. Перечень бесплатно распространяемых программ и их коммерческих аналогов

Программа «free» (версия) Объём[МБ] Интернет-адрес на 19.06.2011 Назначение Коммерческая программа-аналог
7-Zip (v9.20) 1 http://www.7-zip.org/ Упаковка файлов WinZip
AbiWord (v2.8.6) 8 http://abisource.com/download/ Текстовый редактор Microsoft Word
Audacity(vl.3.13) 14 http://audacity.sourceforge.net/ downloadA ta_windows Музыкальный редактор Sound Forge Pro
Avidemux (v2.5.5) 11 http://avidemux.sourceforge.net/download.html Редактор видео Vegas Movie Studio
Dia (v0.97.1) 18 http://dia-installer.de/ Редактор диаграмм Microsoft Visio
Firefox(v4.0.1) 12 http://www.moziUa-europe.org/ ru/firefox/ Интернет-браузер Microsoft Internet Explorer
FreeCommander(v2009.02b) 2 http://www.freecommander. com/fc_downl_en.htm Файловая оболочка Total Commander
GIMP(v2.6.11)  9 http://www.gimp.org/downloads/ Графический редактор Adobe Photoshop
GOM Player (v2.1.27.5031) 8 http://www.gomlab.com/ Просмотр видео Zoom Player Pro
ImgBurn(v2.5.5.0) 6 http://www.imgburn.com/ Запись CD, DVD, Blu-Ray__ Easy CD Creator
IrfanView (v4.28) 9 http: //www. i rfanview. com/ Просмотр графики ACDSee
OpenOffice.org (v3.3.0)________ 147 http://download.openoffice.org/ index.html Работа с документами Microsoft Office

Источник: Рюмик, С. М., 1000 и одна микроконтроллерная схема. Вып. 2 / С. М. Рюмик. — М.:ЛР Додэка-ХХ1, 2011. — 400 с.: ил. + CD. — (Серия «Программируемые системы»).

Источник: http://nauchebe.net/2014/03/sreda-razrabotki-winavr-programmirovanie-na-mk/

WinAVR 20100110

WinAVR 20100110

WinAVR 20100110 – интегрированная среда разработки WinAVR. Включает мощные компиляторы Си и ассемблера, программатор AVRDUDE, отладчик, симулятор и множество других вспомогательных программ и утилит. WinAVR прекрасно интегрируется со средой разработки AVR Studio от Atmel. Ассемблер идентичен по входному коду ассемблеру AVR Studio. Компиляторы Си и ассемблера имеют возможность создания отладочных файлов в формате COFF, что позволяет применять не только встроенные средства, но и использовать мощный симулятор AVR Studio. Еще одним немаловажным плюсом является то, что WinAVR распространяется свободно без ограничений (производители поддерживают GNU General Public License).WinAVR является идеальным выбором для тех, кто начинает осваивать микроконтроллеры AVR. Именно эта среда разработки и рассматривается в качестве основной в данном курсе.Включает следующий набор компонентов:Programmers Notepad – удобный редактор программиста и интегрированная среда разработки (IDE); AVR GCC – компилятор языков C и C++ для AVR; avr-libc – стандартная С библиотека AVR для использования с GCC; avr-as – ассемблер для микроконтроллеров AVR; AVRDUDE – программатор (программа для загрузки и выгрузки кода микроконтроллеров); avrdude-gui – графический интерфейс пользователя для AVRDUDE (только в версиях до WinAVR-20060421 включительно); MFile – автоматический генератор Make-файлов for AVR GCC; GNU Binutils – утилиты для AVR (поддерживают преобразование форматов из ELF в AVR COFF или в AVR Extended COFF); GNU Debugger (GDB) – дебагер (отладчик) с интерфейсом командной строки; Insight – дебагер (отладчик) с графическим интерфейсом пользователя; AVaRICE (JTAG ICE interface) – программа для интерфейсов Atmel JTAG ICE (используется вместе с GDB); SimulAVR – симулятор GDB с поддержкой симулятора от AVR; SRecord – коллекция мощных утилит для загрузки файлов разных форматов в EPROM; Дополнительные вспомогательные программы и утилиты;Набор документации.Платформа: Windows XP, Vista, 7Размер архива: 27,5 мB
 Разный софт | SeryiDVD1771 | 02.10.2015 в 07:08 | 507 | 54

Читайте также:  Простой усилитель низкой частоты

+3
Всего комментариев:

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

Источник: http://seryidvd.narod.ru/load/programmy/raznyj_soft/winavr_20100110/24-1-0-4345

Среда разработки WinAVR

Источник: http://iluhin-sait.narod.ru/sreda_razrabotki_WinAVR/sreda_razrabotki_WinAVR.htm

Ошибка WinAVR [PIC24]

Available Languages?:

Компилятор WinAVR GCC один из самых распространенных Си-компиляторов для микроконтроллеров фирмы AVR. Он был первым кандидатом на портирование OSA. В процессе изучения его особенностей (версия 20090313) была найдена ошибка, которая не позволяет полноценно портировать на него кооперативную ОС.

Что значит “полноценно”? Это значит, что есть возможность использовать ОС только при отключенной оптимизации (ключ компилятору “-o0”). Это очень неприятно, т.к. при включенной оптимизации генерируется код в полтора и более раза компактнее, чем с выключенной.

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

Примечание: В OSA версии 100531 найден механизм обхода проблемы

При наличии такой проблемы встает вопрос целесообразности применения ОС в своем проекте. Мало того, что сама ОС под свои нужды заберет какую-то часть ресурсов (ROM, RAM, время), так еще и остальной код окажется невозможным оптимизировать. При таких условиях результирующий код с использованием ОС и без оптимизации окажется в два раза объемнее, чем без ОС и с оптимизацией.

По причине невозможности (на сегодняшний день) использовать оптимизацию порт OSA для WinAVR большей частью написан на ассемблере. Это немного успокаивает тем, что хотя бы ядро ОС оптимизировано (на сегодня еще есть что оптимизировать, но со временем я доведу порт до максимальной компактности и скорости).

Компилятор WinAVR формирует общий стек для адресов возврата и данных. Когда программа вызывает функцию, использующую локальные переменные, эта функция делает следующее:

  • первым делом сохраняет пару регистров r28:r29 (Y-указатель);

  • затем выделяет стек для локальных переменных (это делается либо командами push для выделения одного байта, либо call $+1 для выделения сразу двух байт);

  • на последнем этапе указатель стека SP копируется в Y-указатель.

Таким образом получается, что на момент начала работы кода функции указатель стека SP и Y-указатель содержат один и тот же адрес.

При дальнейших вызовах (если эта функция будет вызывать другие функции) указатель стека SP будет “расти” вниз, а Y будет выполнять роль указателя фрейма, который располагается “сверху”.

Ниже приведен типичный код инициализации фрейма и схематическое представление его размещения в памяти.

; void func (void) push r28 // Сохраняем в стеке Y-указатель push r29 rcall $+1 // Выделяем фрейм под 5 локальных переменных rcall $+1 push r17 in r28, SPL // Присваиваем Y = SP in r29, SPH …

Это очень удачная модель использования стека, поскольку допускает повторный вход в функцию (в том числе рекурсию). При каждом вызове функция сама себе будет выделять фрейм, гарантируя тем самым непересекаемость областей локальных переменных для любого пути в графе вызовов.

Для обеспечения параллельности выполнения нескольких функций (задач) ОС должна иметь механизм, способный прерывать выполнение функции в середине, передавая управление другим функциям для выполнения, а затем возвращать управление обратно прерванной функции так, чтобы она продолжила свое выполнение с того же места, на котором была прервана.

Разумеется, этот же механизм должен заботиться о сохранении контекста, т.е. помимо программного счетчика должны быть сохранены/восстановлены прочие служебные регистры (указатель стека, регистр статуса, набор регистров общего назначения (РОН)) и локальные переменные.

Со служебными регистрами и РОН все понятно: их набор определен изначально, и с сохранением/восстановлением сложностей не возникает. А вот с локальными переменными сложнее.

В вытесняющих ОС под каждую задачу выделяется своя область стека; это гарантирует сохранность всех локальных переменных и всей истории вызовов для текущей задачи.

Но на малоресурсных контроллерах вытесняющая ОС не заработает из-за отсутствия достаточного объема оперативной памяти для сохранения контекста задач; для таких контроллеров можно использовать ОС с кооперативным планировщиком.

В отличие от вытесняющей ОС, планировщик которой может прервать выполнение задачи в любой момент, в кооперативной ОС переключение задач может произойти только там, где укажет программист. Например:

void Task (void)
{ char x, y; lcd_init(); // инициализация модуля ЖКИ
  OS_Yield(); // передача управления другим задачам (фактически – планировщику)
  x = lcd_getx(); // вывод “Hello world” в строке под курсором y = lcd_gety(); lcd_outtext(x, y + 1, “Hello world”);
  OS_Yield(); // передача управления
  …
}

В данном примере задача может потерять управление только в двух местах: при вызове системного сервиса OS_Yield(). Эта определенность позволяет минимизировать объем сохраняемых при переключении задачи данных. Объем этих данных зависит не только от типа микроконтроллера (программный счетчик, указатель стека и пр.

), но и от особенностей конкретного компилятора. Например WinAVR предполагает, что регистры r2..r17 сохраняются самой функцией (если используются в ней), а регистры r18..r27, r30, r31 – применяются только для сиюминутных операций (т.е. подразумевается, что при возврате из вызываемой функции значения этих регистров будет утеряно).

Это как минимум позволяет при переключении контекста не сохранять эти регистры. Кроме того, WinAVR предоставляет возможность определять некоторые функции с атрибутом __returns_twice__, который избавляет нас от необходимости сохранять и r2..r17. Т.е.

весь сохраняемый контекст будет состоять из: программного счетчика и указателя фрейма (r28:r29).

Остается проблема с локальными переменными. Есть два пути:

  1. применить такой же подход, какой применяется в вытесняющих ОС (т.е. выделять каждой задаче свой стек);

  2. условиться, что время жизни локальных переменных ограничено не телом функции, а интервалом между двумя переключениями задач (в нашем примере выше – между двумя OS_Yield()).

Первый вариант требует наличия сравнительно большого объема оперативной памяти. Т.е. такого объема, который уже позволит использовать вытесняющую ОС, которая гораздо предпочтительнее кооперативной при прочих равных условиях. А вот второй вариант выглядит более приемлемым. Т.е.

мы условились, что переменные x и y будут терять свои значения после каждого вызова OS_Yield() (т.е. после каждой передачи управления планировщику), и если нам понадобится текущая позиция экрана после вызова OS_Yield(), то мы уже не сможем воспользоваться прежними значениями x и y, т.к.

они уже утеряны, и нам нужно будет снова воспользоваться функциями lcd_getx() и lcd_gety().

Почему значения x и y теряются? На этот вопрос мы уже отвечали: потому что в малоресурсных контроллерах приходится использовать одну область памяти для локальных переменных всех задач, и после переключения задачи значения локальных переменных текущей функции просто затрутся значениями локальных переменных параллельно выполняющейся задачи.

Читайте также:  Источники электрического тока

Как быть, если все-таки нужно сохранить значения переменных и после переключения контекста? Очень просто: объявлять из с квалификатором static:

void Task (void)
{ static char x, y; // Объявляем переменные вне стека
  lcd_init(); // инициализация модуля ЖКИ
  OS_Yield(); // передача управления другим задачам (фактически – планировщику)
  x = lcd_getx(); // вывод “Hello world” в строке под курсором y = lcd_gety(); lcd_outtext(x, y + 1, “Hello world”);
  OS_Yield(); // передача управления
  lcd_outtext(x, y + 2, “All animals are equal”); …
}

В этом примере мы не боимся потерять x и y, т.к. они имеют статические адреса и стек других задач их не сможет перетереть.

А теперь мы подошли к самой проблеме.

Компилятор WinAVR в области локальных переменных, помимо переменных, объявленных пользователем, размещает еще и свои временные переменные (которые могут использоваться либо для хранения промежуточных результатов расчетов, либо для сокращения кода). Т.е.

те переменные, к которым программист не имеет прямого доступа и которые он не может объявить как static. Это для кооперативных планировщиков плохо тем, что компилятор не знает, какие из подпрограмм, вызываемых из функции-задачи, передают управление планировщику.

Вернее, есть способ ему об это сказать, объявив такие функции с атрибутом __returns_twice__, но конкретная реализация WinAVR при определенных условиях может это проигнорировать.

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

Для описания ошибки я написал небольшую программу. Я умышленно не стал подключать OSA и сделал все исключительно средствами самого компилятора, а именно – воспользовался парой функций setjmp/longjmp.

Суть программы проста: есть две функции task1 и task2, которые по очереди передают друг другу управление.

Одна функция вызывает подпрограмму, копирующую в строковую переменную Hello слово “HELLO”, а вторая вызывает подпрограмму, копирующую в строковую переменную World слово “WORLD”.

Как работают функции setjmp() и longjmp, надеюсь, объяснять не нужно. В двух словах для тех, кто с ними не знаком:

  • функция setjmp() выполняет сохранение контекста (PC, SP, SREG, r2..r17);

  • функция longjmp() выполняет безусловный переход с восстановлением ранее сохраненного контекста.

(Можно скачать текст программы с файлами проекта для AVR Studio 4.18)

#include
#include
#include
 
//******************************************************************************
// Переменные
//******************************************************************************
 
char Hello[6]; // Буфер для хранения слова “HELLO”
char World[6]; // Буфер для хранения слова “WORLD”
 
 
jmp_buf j_task1, j_task2; // Контекст задач
 
 
//******************************************************************************
// Прототипы функций
//******************************************************************************
 
void task1 (void);
void task2 (void);
void strcpy_hello (char * data) __attribute__((noinline));
void strcpy_world (char * data) __attribute__((noinline));
 
//******************************************************************************
// Функции
//******************************************************************************
 
 
void main (void)
{ task1(); // Инициализируем задачи task2();
  longjmp(j_task1, 1); // Запускаем поочередное выполнение, // начиная с задачи Taks1
}
 
//——————————————————————————
 
void strcpy_hello (char * str) // Cкопировать слово “HELLO” в str
{ str[0] = ‘H’; str[1] = ‘E’; str[2] = ‘L’; str[3] = ‘L’; str[4] = ‘O’; str[5] = 0;
}
 
//——————————————————————————
 
void strcpy_world (char * str) // Cкопировать слово “WORLD” в str
{ str[0] = ‘W’; str[1] = ‘O’; str[2] = ‘R’; str[3] = ‘L’; str[4] = ‘D’; str[5] = 0;
}
 
//——————————————————————————
 
void task1 (void) // ЗАДАЧА 1
{ if (!setjmp(j_task1)) return; // Инициализируем контекст
  for (;;) { Hello[1] ^= Hello[0]; // Обращение к двум элементам массива // на чтение и запись if (!setjmp(j_task1)) longjmp(j_task2, 1); // Переключение контекста strcpy_hello(Hello); // Копируем константу “HELLO” в массив }
}
 
//——————————————————————————
 
void task2 (void) // ЗАДАЧА 2
{ if (!setjmp(j_task2)) return; // Инициализируем контекст
  for (;;) { World[1] ^= World[0]; // Обращение к двум элементам массива // на чтение и запись if (!setjmp(j_task2)) longjmp(j_task1, 1); // Переключение контекста strcpy_world(World); // Копируем константу “WORLD” в массив }
}

Обращу ваше внимание на некоторые моменты:

  • функции strcpy_hello() и strpy_world() объявлены с атрибутом __noinline__, чтобы предотвратить оптимизацию прямой подстановкой тела функции в код, т.к. для синтезирования ошибки нам обязательно нужно, чтобы это были именно вызываемые (через rcall) функции;

  • в функциях task1() и task2() есть бессмысленные строчки: “Hello[1] ^= Hello[0];” и “World[1] ^= World[0];”. Они не несут никакого функционала, просто для синтезирования ошибки нужно, чтобы перед переключением контекста было произведено обращение к нулевому и первому элементам массива, причем нулевой должен быть на чтение, а первый – на запись.

Откройте проект в AVR Studio и соберите его (F7). Установите две точки останова:

Запустите Start-Debugging (Ctlr+Shift+Alt+F5). Далее кнопкой F5 перемещайтесь по программе, а в окне Watch наблюдайте содержимое переменых Hello и World.

Вы увидите, что программа постоянно переключается между функциями task1() и task2().

Но самое главное – вы увидите, что присваиваемые слова “HELLO” и “WORLD” копируются только в одну переменную – World, а переменная Hello остается нетронутой.

Почему?

Рассмотрим листинг функции task1() (листинг task2() аналогичен):

000000c2 :
} //—————————————————————————— void task1 (void) // ЗАДАЧА 1
{ c2: df 93 push r29 c4: cf 93 push r28 c6: 00 d0 rcall .+0 c8: cd b7 in r28, SPL ca: de b7 in r29, SPH cc: 80 e6 ldi r24, 0x60 ; if (!setjmp(j_task1)) return; ce: 90 e0 ldi r25, 0x00 d0: 28 d0 rcall setjmp d2: 89 2b or r24, r25 d4: 29 f4 brne .+10 d6: 0f 90 pop r0 d8: 0f 90 pop r0 da: cf 91 pop r28 dc: df 91 pop r29 de: 08 95 ret ; for (;;) ; { e0: 8d e7 ldi r24, 0x7D ; примечание: 0x7D – адрес переменной Hello e2: 90 e0 ldi r25, 0x00 ; e4: 89 83 std Y+1, r24 ; e6: 9a 83 std Y+2, r25 ; e8: 03 c0 rjmp .+6 ; ea: 89 81 ldd r24, Y+1 ; strcpy_hello(Hello); ec: 9a 81 ldd r25, Y+2 ; ee: a5 df rcall strcpy_hello ; f0: ed e7 ldi r30, 0x7D ; Hello[1] ^= Hello[0]; f2: f0 e0 ldi r31, 0x00 ; f4: 80 81 ld r24, Z f6: ee e7 ldi r30, 0x7E ; f8: f0 e0 ldi r31, 0x00 ; fa: 90 81 ld r25, Z fc: 89 27 eor r24, r25 fe: 80 83 st Z, r24 100: 80 e6 ldi r24, 0x60 ; if (!setjmp(j_task1)) 102: 90 e0 ldi r25, 0x00 ; 104: 0e d0 rcall setjmp ; 106: 89 2b or r24, r25 108: 81 f7 brne 0xEA 10a: 83 e8 ldi r24, 0x83 ; longjmp(j_task2, 1); 10c: 90 e0 ldi r25, 0x00 ; 10e: 61 e0 ldi r22, 0x01 ; 110: 70 e0 ldi r23, 0x00 ; 112: 28 d0 rcall longjmp ;

В адресах 0xC2..0xCA производится выделение 2-байтового фрейма в стеке. Далее, в адресах 0xCC..0xDE производится формирование контекста. Нас же интересует работа программы в адресах 0xE0..0x112, т.е. работа цикла.

Сразу же обратим внимание на код 0xE0..0xE6, в котором адрес строки Hello копируется во временную локальную переменную [Y+1]:[Y+2] (еще раз посмотрим код и убедимся, что сами мы локальных переменных не создавали).

Далее (адрес 0xE8) происходит переход на операцию Hello[1]^=Hello[0] (адреса 0xF0..0xFE), затем попадаем на сохранение контекста setjmp() (0x100..0x104) и передачу управления задаче task2() через longjmp() (0x10A..

0x112).

При передаче управления восстанавливается контекст для функции task2, в том числе указатель фрейма r28:r29 (т.е. Y). Т.к. функции идентичны, то и фрейм для них будет одного размера (2 байта) и расположен по одним и тем же адресам.

Функция task2() выполняет абсолютно те же действия, что и task1(), а что самое главное – производит копирование адреса переменной World во временную переменную [Y+1]:[Y+2], затирая значение, записанное туда функцией task1().

Дойдя тем же путем, что и task1(), до вызова longjmp(), функция task2() передает управление task1() через сохраненный контекст j_task1.

Тут и начинаются проблемы. Программный счетчик восстанавливается и указывает на следующую за вызовом setjmp() команду, т.е. на адрес 0x89. После чего выполняется переход на адрес 0xEA (после перехода longjmp() r25 != r24), где и располагается вызов функции копирования строки strcpy_hello().

Обратите внимание, что в качестве параметра ей передается не фактический адрес переменной Hello, а значение, запомненное во временной переменной [Y+1]:[Y+2], т.е. то, которое было перетерто функцией task2(), и теперь по этим адресам хранится адрес не переменной Hello, а переменной World.

Поэтому функция strcpy_hello запишет слово “HELLO” в переменную World, а не в Hello.

Вот такая проблема.

Хоть я и создал пример, синтезирующий описанную ошибку, но мне так и не удалось четко сформулировать условия ее проявления. Попробуйте модифицировать код (например, убрать выражение Hello[1] ^= Hello[0], или поменять в нем индексы, или убрать setjmp/longjmp) и программа заработает, т.е.

начнет передавать в функцию strcpy_hello() фактический адрес переменной, а не его копию. Т.е. я не могу точно сказать, что в таком-то случае ошибка будет проявляться, а в таком не будет.

Заметить удалось только то, что между выражением, обращающимся к тому же адресу, что и вызов функции strcpy_hello(), должен находиться вызов функции с атрибутом __returns_twice__.

Учитывая, что атрибут функции __returns_twice__ говорит компилятору, что все значения регистров теряются после возврата из такой функции, предполагается, что он в курсе насчет того, что и локальные переменные могут быть утеряны. Из описания:

Источник: http://www.pic24.ru/doku.php/osa/articles/winavr_bug

Источник

Спасибо за ваше внимание к сайту нашим новым публикациям.