Главная arrow Начинающим arrow Что это? Как это? Почему это? arrow Закидон протеуса  
18.05.2024 г.
Главная
Проекты
Статьи
Начинающим
Архив новостей
Ссылки
Контакты
Поиск
Файлы
Форум
Карта сайта
Авторизация





Забыли пароль?
Ещё не зарегистрированы? Регистрация
Поддержи наш сайт!
Через WebMoney

 R785211844650
 Z210696637574
 E368177590409

Закидон протеуса Печать E-mail
Рейтинг: / 16
ХудшаяЛучшая 
Автор ARV   
04.07.2009 г.

Многие начинающие (и не только) разработчики программ для микроконтроллеров AVR используют для отладки программу PROTEUS ISIS. Все бы ничего, но порой это приносит массу неприятных ощущений, когда вроде бы абсолютно верная программа не работает в протеусе, но, что самое странное, работает в реально спаянной схеме.

Данная статья проливает свет на пару проблем, свойственных PROTEUS 7.4 SP3.

Пишем программу такого содержимого (в конце статьи есть архив со всеми упоминаемыми исходниками):

#include <avr/io.h>
#include <math.h>
#include "com_io.h"

int main(void){
   float a1, arg;
   int i;
   for(i = 0; i<360; i++){
      arg = 2*M_PI*i/360;
      a1 = sin(arg) + i;
      printf("%3d : %f %f\n",i,a1,cos(arg)); // эта строка не будет работать в протеусе
      //printf("%f\n",3.14/i); // эта строка будет работать всегда
   }
}

Файл com_io.h в приложении, в нем ничего занимательного нет (хотя, есть один момент, о нем позже).

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

Не забываем указать тактовую частоту процессора 8МГц и оптимизацию по размеру (-Os), после чего компилируем в WinAVR эту программу, обязательно используя в командной строке параметры -Wl,-u,vfprintf -lprintf_flt -lm , которые всего-навсего заставят компоновщик прилинковать библиотеку для форматированного вывода чисел с плавающей точкой. Заодно это увеличит размер - это важно, т.к. с малым размером кода эффект не будет заметен.

Получаем следующий результат компиляции (для atmega8):

AVR Memory Usage
----------------
Device: atmega8
Program: 7158 bytes (87.4% Full)
(.text + .data + .bootloader)
Data: 298 bytes (29.1% Full)
(.data + .bss + .noinit)

Если у вас есть возможность, зашиваем прошивку в МК и убеждаемся, что все работает - в терминале табличка чисел появляется. Теперь берем протеус.

В протеусе рисуем схемку из МК atmega8 и виртуального терминала, настраиваем скорость терминала на 38400 бод, для МК задаем тактовую частоту 8MHz и загружаем в него полученный elf-файл. Можно и hex, но тогда не получится «вычислить» место проблемы.

При попытке просто запустить программу на исполнение протеус мгновенно выдает сообщение об ошибке: Invalid opcode 0xFFFF at PC=0x21AA.

 

Берем калькулятор Windows и элементарно вычисляем, что адрес 0x21AA соответствует числу 8616, что реально больше имеющейся в меге8 памяти в 8192 байта. Ясен-красен, что вне объема FLASH никаких команд быть не может. Но каким образом верно работающая программа (см. проверку в железе) вдруг выскакивает за пределы памяти программ?

Попробуем разобраться.

В протеусе начинаем проходить программу по шагам. Доходим до строки программы printf("%3d : %f %f\n",i,a1,cos(arg)), и при помощи всплывающего меню заставляем протеус показать дизассемблированные команды (т.е. делаем команду Disassembly). Начинаем исполнять по одной ассемблерной команде, нажимая F11 (это важно: не F10, а F11). С некоторого момента протеус начинает сообщать, что текста исходника для соответствующей команды нет - это значит, что мы забрались внутрь библиотечной функции printf. Не беда, адрес текущей команды протеус все равно показывает - вот тут начинается самое интересное, будьте внимательны!

Чтобы найти место проблемы, придется записывать адреса каждой команды, чтобы обнаружить ту, после исполнения которой протеус улетает за пределы памяти. Слава богу, этих команд не так и много - штук 20. Если версия WinAVR у вас не такая, как у меня, адрес «страшной» команды может быть иным, а у меня он был 0х166С - именно после исполнения команды по этому адресу прогрммный счетчик становился равным 0x21A8, т.е. протеус съезжал с катушек.

Теперь открываем lss-файл нашей программы (листинг) и ищем строку с адресом 0x166C. Видим следующее:

166a: af 01 movw r20, r30
166c: 9d d5 rcall .+2874 ; 0x21a8 <__data_load_end+0x5b2>
166e: 20 96 adiw r28, 0x00 ; 0

Даже по комментариям видно, что вызов подпрограммы осуществляется каким-то диким образом: смещение в команде rcall не может быть больше - а у нас число 2874!!! Неужели WinAVR подвел? Нет, вспоминайте: в железе все пашет.

Теперь давайте освежим в памяти, как ядро AVR работает с программным счетчиком. Если есть желание - читайте даташиты и апноуты, а если нет - я вам скажу сразу все. В программном счетчике ядра AVR физически отсутствуют старшие биты, т.е. счетчик, досчитав до «предела», переполняется и попадает в нулевой адрес. Поэтому попытка занести в PC значение больше 8192 приведет к тому, что в PC занесется значение на 8192 меньше: заносим 10000, реально заносится 10000-8192=1808. Иными словами, невозможно «заслать» программу в отсутствующие физически ячейки FLASH.

Попробуем при помощи только что описанной математики и листинга вычислить, куда же хочет перейти программа в строке

166c: 9d d5 rcall .+2874 ; 0x21a8 <__data_load_end+0x5b2>

Переведем все числа в десятичные (для простоты) и вычислим правильный адрес.

Текущий адрес 0х166С = 5740, не забываем, что переход осуществляется относительно значения PC после загрузки этой команды, поэтому адрес перехода будет 5740 + 2 + 2874 = 8616, что больше, чем доступный объем 8192, поэтому вычтем из него «поправку»: 8614 - 8192 = 424 или 0x01A8. Таким образом, на самом деле переход осуществляется к адресу 0x01A8. Смотрим в листинг:

000001a8 <vfprintf> :
1a8: a1 e1 ldi r26, 0x11 ; 17
1aa: b0 e0 ldi r27, 0x00 ; 0

То есть всего-навсего вызывается библиотечная функция форматирования для printf - никакого криминала!!!

Вывод: PROTEUS 7.4 SP3 неправильно имитирует работу аппаратного программного счетчика ядра микроконтроллеров AVR.

К сожалению, это очень сильно мешает отладке, и побороть какими-то извратами эту ситуацию невозможно.

Однако, это не все сюрпризы протеуса!!!

 

Вот еще один. В начале я сообщал, что в файле com_io.c имеется нюансик. Откройте его и посмотрите сразу в конец: там есть функция инициализации модуля USART:

/// Функция настройки USART
__attribute__((naked, section(".init7")))
void init_io(void){
   /// Вызывать эту функцию из основной программы не надо - она автоматическая!
   UCSRA = 0; // *******
#include 
   UBRRH = UBRRH_VALUE;
   UBRRL = UBRRL_VALUE;
#if USE_2X
   UCSRA |= (1 << U2X);
#else
   UCSRA &= ~(1 << U2X);
#endif
   UCSRB |= _BV(TXEN);
#if ONLY_OUT == 0
   UCSRB |= _BV(RXEN);
#endif
   UCSRC = 0x86; // *******
   
stdout = &mystdout;
   stdin = stdout;
}

Обратите внимание на строки, отмеченные звездочками. Если открыть даташит на МК, то можно увидеть, что после сброса содержимое UCSRA обнулено, а UCSRC инициализируется числом 0x86. Вопрос на засыпку: зачем в программе записывать в эти регистры числа, которые там и так присутствуют? Ответ: без этого в протеусе не будет работать! Вы можете убедиться в этом сами: закомментируйте эти строки и попробуйте в протеусе и в железе. Почему так происходит? Видимо, по той же причине - баг протеуса.

На этом все. Удачи в отладке!

Архив с файлами исходников, проектом AVR Studio и проектом протеуса.


Добавить в любимые (0) | Просмотров: 29734

  Коментарии (1)
 1 Написал(а) Владимир, в 18:11 31.03.2011
Еще есть баг с переменными, непонятно почему протеус ругается вот так, например для переменной i тип int:  
i R-63738:R-63737 word Item (2 bytes at 0xFFFF0706) not within memory block (0x000000E0 bytes).

Только зарегистрированные пользователи могут оставлять коментарии.
Пожалуйста зарегистрируйтесь или войдите в ваш аккаунт.

 
След. »
Полезные материалы по сходным темам
Кто на сайте?
Помощь on-line
BannerFans.com