Работа с Simulavr

gdb_emacs_assembler.png

При работе с AVR многие начинают с прекрасного учебника от DiHALT , но хотя на linux можно запустить AVRStudio, давайте попробуем моделировать поведение микросхемы с помощью свободного проекта simulavr. Также на linux есть программы для внутрисхемной отладки с помощью JTAG (openOCD) но для них нужны дополнительно адаптеры.

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

А вот как залезаешь под капот embended тусовки linux, сразу начинается: рытьё форумных сказаний на AVRFreaks и кусков документации.

Да я знаю что есть плагин к Eclipse и Eclipse сборки, но я работаю в Emacs, а кто-то в Vim , а кто-то вообще ed использует…. вот и все что я хотел сказать. Только Makefile, только хардкор!

Через терни к звездам.

http://www.cs.karelia.ru/~vadim/unix/emacs_gdb.php.ru

SimulAVR

Установка

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

Требования

  • gcc
  • autoconf
  • zlib-dev
  • libtool
  • swig (для python интерфейса)
  • avr-gcc
  • avr-gdb
  • avr-libc
  • tk-*-dev (для TCL интерфейса но я не видел примеры его использования)
  • tk-dev
  • xotcl-shells
  • itcl

У меня не захотел компилироваться тарбол поэтому я стянул свежую и исправленную версию с git хранилища.

git clone git://git.savannah.nongnu.org/simulavr.git
cd simulavr
./bootstrap

Посмотрим список доступных переменных для конфигурации

./configure --help

Самое время озаботиться поддержкой Verilog ,Python и это весьма геморройный пунктик, например на Ubuntu 13.04 он не смог найти пути к python библиотекам, вот так можно их указать вручную.

./configure LDFLAGS="-L/usr/lib/python2.7" --enable-python --enable-tcl 
make
make install

Установка Python интерфейса. Да его надо ставить отдельно даже если вы включили опциюю –enable-python при конфигурации

cd simulavr/src
sudo python setup.py install

Правим код!

«Детка это же опенсорс» (с), я отправил патч и замечания разработчикам, мне интересно как они на это отреагируют. В примере ниже я использовал Atmega16 ,а в ней PINB ,PIND для того чтобы они заработали пришлось следующим образом изменить строки с настройками

Файл /simulavr/src/atmega16_32.cpp

     porta = new HWPort(this, "A");
-    portb = new HWPort(this, "B");
+    portb = new HWPort(this, "B",true);
     portc = new HWPort(this, "C");
-    portd = new HWPort(this, "D");
+    portd = new HWPort(this, "D",true);

Файл /simulavr/src/atmega16_32.cpp

 void HWPort::SetPin(unsigned char val) {
     if(portToggleFeature) {
-        port ^= val;
         CalcOutputs();
-        port_reg.hardwareChange(port);
+        pin = val;
+       port_reg.hardwareChange(pin);
     } else
         avr_warning("Writing of 'PORT%s.PIN' (with %d) is not supported.", myName.c_str(), val);
 }

Странно , почему у них там по умолчанию залочена возможность менять значение PIN-ов portToggleFeature=False , поэтому глобально менять ничего не стал.

Подготовка (компиляция)

Итак у нас есть некий файл с кодом на ассемблере и нам необходимо его отладить с помощью gdb.

avr-gcc -Wa -ggdb -mmcu=atmega16a example.S -o example.o

Смотрим справку и видим:

  • -Wa или -Xassembler опция которая говорит сишному препроцессору что у нас в коде есть ассемблер… есть ещё конечно команда для компиляции ассемблера вроде avr-as но её вызов работает не корректно.
  • -ggdb а иногда просто -g это добавление отладочной информации в бинарник, иначе не удастся связать ассемблерные команды и тест написаны например на Си
  • -mmcu тип процессора, подробней в справке.

Запуск

simulavr -g -d atmega16

Что здесь написано:

  • -g или –gdbserver ‘запускает gdb сервер которые ждет соединения по умолчанию через порт 1212
  • -d или –device после этого указывается название микроконтроллера из поддерживаемых(список -L)
  • Раньше ещё была опция -P simulavr-disp для отображения всех регистров, но её убрали.

Теперь воспользуемся gdb, полный код примера example.S приведен в конце статьи , пример был использован из книги В.Я. Хартова «Микроконтроллеры AVR. Практикум для начинающих», пример переработан и изменен под использование с GNU As

Запуск GDB

avr-gdb --annotate=3 example.o

> target remote localhost:1212
> load
> b waitstart
> continue

Что мы сделали, подключились к удаленному серверу gdb , load загрузили туда нашу программу, поставили точку останова на метке waitstart и начали выполнение программы вплоть до точки останова continue. Пошаговое выполнение производиться командой next или n (где мы не входим в вызываемы функции) или step где мы переходим в вызываемые функции.

У меня в Emacs GUD отображаются изменение всех регистров, в консольном режиме info registers поможет рассмотреть состояние всех регистров. Но к сожалению там нет портов, поэтому смотрим даташит(спецификацию) на Atmega16 и узнаем что PORTD обладает адресом 0x32, DDRD=0x31,а PIND=0x30.

Как это посмотреть и поменять в пошаговом режиме.

> x/xb 0x32
0x800032:    0x03
> set {char}0x32=0xf0
> x/xb 0x32
0x800032:    0xf0
> set {char}0x30=0xf0
> x/xb 0x30
0x800030:    0xf0

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

#include <avr/io.h>
;; #include <compat/deprecated.h>
#define SFR(X) _SFR_IO_ADDR(X)
#define reg_led r20             
#define temp r16                
#define START 0
#define STOP 1
;; .includepath "/usr/share/avra/includes/" ;Папка с файлами заголовками
;; .include "m16def.inc" ; Используем ATMega16
;; Переключение светодиодов при нажатии на кнопку START
        ;; .def temp =r16
        ;; .def reg_led = r20
        ;; .equ START = 0
        ;; .equ STOP = 1
        ;; .org $000      ;устанавливает начальный адрес первого сегмента
        .section .text
        .global  main

        ;; rjmp init
        ;; Инициализация
main:   ldi reg_led, 0xfe       ;сброс reg_led.0 для включения LED.0
        sec                     ;C=1
        set                     ;T=1 - флаг направления
        ser temp                ;temp = 0xFF
        out SFR(DDRB),temp      ;порта PB на вывод
        out SFR(PORTB), temp    ;погасить LED
        clr temp                ;temp = 0x00
        out SFR(DDRD),temp      ;??переключаем порт D на вход
        ldi temp,0x03           ;включение подтягивающих резисторов
        out SFR(PORTD), temp    ;порта D
waitstart:
        sbic SFR(PIND),START            ;прыжок на +2 если PIND.START==0
        rjmp waitstart

loop:
        out SFR(PORTB),reg_led

;; Задержка в тактах
;; TIME=ldi+(ldi+(dec+brne)*B+dec+brne)*A
        ldi r17,2
d1:     ldi r18,2
d2:     dec r18                 ;r18--
        brne d2                 ;перейти на d2 если r18 != 0
        dec r17                 ;r17--
        brne d1                 ;перейти на d1 если r17 != 0

        sbic SFR(PIND),STOP             ;прыжок +2 если PIND.STOP == 0
        rjmp MM                 ;то переход
        rjmp waitstart          ;для проверки кнопки START
MM:                             ;
        ser temp                ;temp=0xFF
        out SFR(PORTB),temp             ;
        brts left               ;brts - перейти если флаг Т==1
        sbrs reg_led,0          ;прыгуть +2 если reg_led.0 == 1

        set                     ;T=1
        ror reg_led
        rjmp loop
left:
        sbrs reg_led,7          ;прыгуть +2 если reg_led.7 == 1
        clt                     ;T=0
        rol reg_led             ;сдвиг в <- в лево с переносом
        rjmp loop

Прерывания

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

call __vector_1()

Номер вектора можно узнать из даташита к контроллеру(номер N-1 так как первое прерывание это reset, так для INT0 это 1), в программе же представлены стандартные для препроцессора C имена. (Смотри Note 7)

avr-objdump -d -m avr5 examplevec.o

Исходный код с кодом для тестирования. Вопросы разработчиком я отослал и вообще посоветовал им wiki завести,но ответа пока нет.

#include <avr/io.h>
#include <avr/interrupt.h>      
;; В примере используется обработка прерываний, нажатие INT0(stop)
;; #include <compat/deprecated.h>

#define SFR(X) _SFR_IO_ADDR(X)  ;Обращение к регистрам ввода вывода только через это
;; И оно не сработало пришлось вручную все заменить.... непонятно
;; Нужен ручной препроцессор здесь он не справляется т.е дополнительный .h файл
#define reg_led r20             
#define temp r16                
#define START 0
        .section .text
        .global  main

;;###############Основная программа
main:   ldi     reg_led,0xfe
        ldi     temp,pm_lo8(RAMEND)     ;RAMEnd константа окончания RAM памяти
        out     _SFR_IO_ADDR(SPL),temp
        ldi     temp,pm_hi8(RAMEND)     ;
        out     _SFR_IO_ADDR(SPH),temp
        sec
        set
        ser     temp
        out     _SFR_IO_ADDR(DDRB),temp
        out     _SFR_IO_ADDR(PORTB),temp
        clr     temp
        out     _SFR_IO_ADDR(DDRD),temp
        ldi     temp,0x05
        out     _SFR_IO_ADDR(PORTD),temp
        ldi     temp,0x40                       ;Установка битов INT1, INT0 или INT2 разрешает прерывания 
                                                ;0100 0000
        /*
        Условия генерации прерываний устанавливаются с помощью  конфигурационных регистров.
        Для INT0, INT1 – это регистр MCUCR (MCU Control Register).
        Для INT2 – MCUCSR (MCU Control and Status Register)     
        */

        out     _SFR_IO_ADDR(GICR),temp         ;от процессора лучше это отдать макросам
        ldi     temp,0x00                       ;ISC01, ISC00 для INT
        out     _SFR_IO_ADDR(MCUCR),temp
        sei
waitstart:
        sbic    _SFR_IO_ADDR(PIND),START
        rjmp    waitstart
loop:   out     _SFR_IO_ADDR(PORTB),reg_led
        rcall   delay
        ser     temp
        out     _SFR_IO_ADDR(PORTB),temp
        brts    left
        sbrs    reg_led,0

        set
        ror     reg_led
        rjmp    loop

left:   sbrs    reg_led,7

        clt
        rol     reg_led
        rjmp    loop

;;###############Функция задержки
delay:  ldi     r17,250
d1:     ldi     r18,250
d2:     dec     r18
        brne    d2
        dec     r17
        brne    d1
        ret


        .global INT0_vect       ;Название взято отсюда
        ;; www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
;;###############Обработка прерывания INT0
INT0_vect:
waitstart2:
        sbic    _SFR_IO_ADDR(PIND),START
        rjmp    waitstart2
        reti

        .end

Вспомогательные инструменты

Emacs GUD

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

Позже выложу видео о том как работать во всем этот великолепии.

Makefile и gdbinit

Красивый Makefile для embended проекта там создается инициализационный файл для gdb который убирает в себя рутинные операции.

GDBINITFILE=gdbinit-$(PROJECTNAME)
gdbserver: gdbinit
	simulavr --device $(MCU_TARGET) --gdbserver

gdbinit: $(GDBINITFILE)

$(GDBINITFILE): $(PRG).hex
	@echo "file $(PRG).elf" > $(GDBINITFILE)

	@echo "target remote localhost:1212" >> $(GDBINITFILE)
	@echo "load"                         >> $(GDBINITFILE)
	@echo "break main"                   >> $(GDBINITFILE)
	@echo
	@echo "Use 'avr-gdb -x $(GDBINITFILE)'"

Т.е. теперь запуская GDB командой avr-gdb -x имя\_файла\_gdbinit

Это только первые и робкие примеры и шаги в этом направления, я ничего не сказал о DDD а также о том как можно раздуть конфиг к GDB до 4000 строк. Это постараемся добавить сюда по мере освоения.

10 Comments

  1. Классная статья. Благодаря ей у меня получиось установить simulavr. Хочу поделиться своим опытом. За место —enable-python я написал —enable-python 2.7 и мне не пришлось прописывать пути. Пользуюсь Ubuntu 14, мне еще пришлось установить makeinfo, не хватало. make install не работает. А вот sudo make install заработало. sudo python setup.py install — эта строчка выдает ошибку. -Wa у меня avr-gcc не знает. И второго блока кода, который нужно исправить, в atmega16_32.cpp у меня нет. Хотелось бы видео на YouTube посмотреть, как вы пользуетесь отладкой с помощью simulavr.

    • Sergey

      16.07.2014 at 00:17

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

      Сейчас попытаюсь снова оживить UISP … (туда добавили АЦП), а также постараюсь разобраться с этой платой http://starterkit.ru/html/index.php?name=shop&op=view&id=32

      Если у Вас что-то получилось с simulavr ,отпищите это и выложите где-нибудь, рассылка simulavr жива… но они на мои вопросы так и не смогли ответить.

  2. Спасибо, просто клад ,а не статья. :)

  3. Отличная статья. Особенно для тех, кто только начинает знакомится и с МК и с linux. Спасибо.
    Скажите, а что это за скриншот «вкусной» среды для работы с AVR в самом начале статьи? ОООчень интересно.
    Похоже на emacs… но как?

    • Valber

      11.03.2016 at 12:52

      Это Emacs GUD https://www.gnu.org/software/emacs/manual/html_node/emacs/GDB-Graphical-Interface.html#GDB-Graphical-Interface он заппускается из консоли M-x gdb дальше там нужно будет ввести команду подключения к avr-gdb и прочее.
      Пользовался им очень давно, как раз для этого теста, может быть вернусь и видео запишу.

      • Эх, статейку бы небольшую…:)
        Но и за видео буду премного благодарен.
        Перелопатил много инета, но практических описаний связки emacs + avr-gcc + simulavr+avr-gdb толком не нашел. Понятно, что при хорошем знании emacs эти связки скорее всего тривиальны.
        Буду копать emacs.

        • Valber

          11.03.2016 at 15:49

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

          Если допустим есть какая-то система с другой архитектурой но нам нужно отладить приложение на ней, тогда используется GDB сервер, т.е. программа исполняется на той системе, а наружу мы можем по сети отправлять отладчику команды.

          Это наш случай ,в данном случаем мы запускаем эмулятор работы AVR наружу он общается так как будто запущен GDB сервер.

          M-x gdb
          avr-gdb —annotate=3 example.o
          дальше уже консоль вводим подключение к удаленному серверу отладки
          target remote localhost:1212

          Все что вам нужно посмотреть, потыкать справку по GUD и видео посмотреть, если Вы работали с какими нибудь средами отладки думаю интуитивно кое что поймете.

          • Огромное спасибо!
            Определенная ясность появилась
            Буду копать :)

  4. Прежде чем приступить к его отладке, надо сделать кое-какие настройки Eclipse . Прежде всего, автоматизировать запуск simulavr — вам ведь не захочется всякий раз запускать его средствами Windows, тем более что иной раз эта утилитка подвисает и надо ее «убивать» принудительно.

Добавить комментарий

Your email address will not be published.

*

*

© 2017 Crafting.be

Theme by Anders NorénUp ↑