Отладка скетчей Arduino

Библиотека Simple Dumping Monitor для Arduino-совместимых контроллеров на базе микроконтроллеров ATmega позволяет выводить дампы регистров, таймеров и памяти RAM, Flash и EEPROM, а также дамп таблицы векторов прерываний.

О библиотеке Simple Dumping Monitor

Библиотекой версии 0.21 поддерживаются микроконтроллеры:

  • ATmega48P/88P/168P/328P -- платы Arduino

  • ATmega640/1280/1281/2560/2561 -- платы Arduino MEGA

  • ATmega16U4/32U4 -- платы Arduino Leonardo

  • ATmega164A/PA/324A/PA/644A/PA/1284/P -- платы Sanguino/Daiduino

Начиная с версии 0.6 в библиотеку добавлены функции простого символьного отладчика.

В скомпилированном виде библиотека занимает около 11 Кб памяти (около 15 Кб - Arduino Mega). Требования к ОЗУ (RAM) не превышают 1 Кбайт (277 байт для примера dumpmon.pde, 377 байт для примера dumpmonDebug.pde).

Установка библиотеки Simple Dumping Monitor

Для использования библиотеки, нужно скачать файл с архивом. В архиве находится папка DumpMon, которую нужно распаковать в директорий libraries директория с библиотеками Arduino IDE. В результате должно получиться libraries/DumpMon.

В папке DumpMon/Examples находится скетч-пример dumpmonDebug.pde, который демонстрирует использование библиотеки для отладки скетча.

Команды отладчика библиотеки Simple Dumping Monitor

После успешной компиляции скетча и загрузки его в память Arduino, нужно открыть окно Serial Monitor, включить нужную скорость обмена (в примерах используется скорость 19200 бод). После этого можно отправлять Arduino команды для просмотра наблюдаемых переменных и управления отладкой:

  • ? -- вывод подсказки.

  • W -- вывод значений наблюдаемых переменных.

  • S -- перевод отладчика в режим пошагового выполнения.

  • N -- выполнить программу до следующей точки останова.

  • G -- выполнение программы в обычном режиме.

  • A -- повторить предыдущую команду.

  • С -- продолжить вывод дампа (для команды W -- повторить вывод).

Команды и адреса можно вводить как в нижнем, так и в верхнем регистрах. Значения переменных и адресов выводятся в шестнадцатиричном формате.

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

Инициализация библиотеки Simple Dumping Monitor

Для использования отладчика библиотеки Simple Dumping Monitor, необходимо добавить в функцию setup() скетча вызов функции инициализации библиотеки, а также добавить переменные для наблюдения в список наблюдаемых переменных.

#include <dumpmon.h> // Подключение библиотеки к скетчу


#define LEDPIN 13 // Светодиод на контакте Digital 13


int count = 0; // 16-битная переменная целого счётчика

long lcount = 0; // 32-битная переменная целого счётчика

char* text = "Debug"; // Строковая переменная


void setup()

{

pinMode(LEDPIN, OUTPUT); // Контакт светодиода в режим вывода

dumpmonSetup(19200); // Инициализация библиотеки DumpMon

watch(&count, "count"); // Добавить в список наблюдения адрес переменной типа int

watch(&lcount, "lcount"); // Добавить в список наблюдения адрес переменной типа long

watch(&text, "text"); // Добавить в список наблюдения адрес указателя на строку

watch(&PORTB, "PORTB"); // Добавить в список наблюдения регистр порта B

// (бит 5 соответствует контакту Digital 13)

}

Функция dumpmonSetup() принимает два параметра:

  • Скорость обмена последовательного порта USART в бодах (бит/сек.).

  • Начальный режим отладчика (по умолчанию - пошаговый, что соответствует значению STEP_MODE).

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

dumpmonSetup(19200, GO_MODE); // Инициализация библиотеки DumpMon

По умолчанию библиотека использует последовательный порт Serial (USART0). Для использования другого последовательного порта микроконтроллеров ATmega1280/2560 (Serial1, Serial2 или Serial3) следует добавить в вызов функции dumpmonSetup() ссылку на данный порт:

dumpmonSetup(&Serial2, 19200, GO_MODE); // Инициализация библиотеки DumpMon

// для коммуникации через порт Serial2

Точки останова

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

void loop()

{

++count; // Увеличение счётчиков на единицу

++lcount;

breakpoint("counters watch"); // Точка останова

if (count & 1) // Изменяем значение строковой переменной при нечётном значении счётчика

text = "Example";

else

text = "Debug";

breakpoint("text watch"); // Ещё одна точка останова

if (count & 5) // Мигаем светодиодом достаточно быстро для пошаговой отладки

digitalWrite(LEDPIN, HIGH);

else

digitalWrite(LEDPIN, LOW);

}

Примечание. Вызывать функцию breakpoint() из функций-обработчиков прерываний не следует, работать не будет.

Сессия отладки с библиотекой Simple Dumping Monitor

После успешной компиляции и загрузки скетча в память Arduino, для начала отладки следует открыть окно Serial Monitor (меню Tools), и установить скорость обмена, используемую в скетче. В данном случае 19200 бод (бит/сек.).

В окне Serial Monitor мы увидим информацию об очередной точке останова:

<0> counters watch

0158 count 0001 ".."

015A lcoun 00000001 "...."

0140 text "Debug"

0025 PORTB 00 "."

Введём команду N и нажмём клавишу Enter или кнопку Send, чтобы передать её Arduino.

<1> text watch

0158 count 0001 ".."

015A lcoun 00000001 "...."

0140 text "Example"

0025 PORTB 00 "."

Теперь понятно, что выводит отладчик. Первой строкой выводится номер останова и идентификатор точки останова. Затем выводится дамп переменных наблюдения в формате: адрес переменной, символьная метка, значение в шестнадцатиричном формате и значение в символах ASCII. Для строковых переменных значение выводится в виде ASCII-текста.

Посмотрим память по адресу переменной text, отправив команду M140. Отладчик выведет дамп памяти, начиная с адреса 0x0140.

Memory dump: RAM

0140 27 01 00 00 08 00 00 00 00 00 43 16 76 14 8F 14 '.........C.v...

0150 E3 15 10 16 F6 15 32 16 01 00 01 00 00 00 40 01 ......2.......@.

0160 03 03 04 00 58 01 5A 01 40 01 25 00 00 00 00 00 ....X.Z.@.%.....

0170 00 00 00 00 63 6F 75 6E 74 6C 63 6F 75 6E 74 65 ....countlcounte

0180 78 74 00 50 4F 52 54 42 00 00 00 00 00 00 00 00 xt.PORTB........

0190 00 00 00 00 00 00 00 00 00 00 00 00 01 03 FF 00 ................

01A0 00 00 00 00 02 00 01 00 00 6E 6D 31 34 30 30 00 .........nm1400.

01B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

0200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

0210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

0220 00 00 00 00 00 00 00 00 00 06 00 05 00 4A 01 A9 .............J..

0230 01 C5 00 C4 00 C0 00 C1 00 C6 00 04 03 07 05 01 ................

Поскольку переменная text имеет тип указателя на массив символов типа char, то значение 0x0127 - это адрес строки, на которую указывает переменная text в данный момент. Выведем дамп командой M127.

Memory dump: RAM

0127 45 78 61 6D 70 6C 65 00 44 65 62 75 67 00 74 65 Example.Debug.te

0137 78 74 20 77 61 74 63 68 00 27 01 00 00 00 00 00 xt watch.'......

0147 00 00 00 43 16 76 14 8F 14 E3 15 10 16 F6 15 32 ...C.v.........2

0157 16 01 00 01 00 00 00 27 01 03 03 04 00 58 01 5A .......'.....X.Z

0167 01 40 01 25 00 00 00 00 00 00 00 00 00 63 6F 75 .@.%.........cou

0177 6E 74 6C 63 6F 75 6E 74 65 78 74 00 50 4F 52 54 ntlcountext.PORT

0187 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 B...............

0197 00 00 00 00 00 01 03 FF 00 00 00 00 00 02 00 01 ................

01A7 00 00 6E 6D 31 34 30 30 6D 31 32 37 00 00 00 00 ..nm1400m127....

01B7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01C7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01D7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01E7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

01F7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

0207 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

0217 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

Снова выведем список переменных наблюдения командой W:

0158 count 0001 ".."

015A lcoun 00000001 "...."

0140 text "Example"

0025 PORTB 00 "."

Всё верно - строковая константа "Example" хранится в RAM по адресу 0x0127, на который в данный момент указывает переменная text.

Запустим скетч на выполнение командой G. Затем остановим его командой S или N.

<2> text watch

0158 count 2D22 ""-"

015A lcoun 00022D22 ""-.."

0140 text "Debug"

0025 PORTB 20 " "

Значения счётчиков совпадают в младших 16 битах. По старшим 16 битам счётчика lcount можно увидеть, что за это время счётчик count успел несколько раз обнулиться. В моём случае это 2 раза. А также переменная текст имеет значение "Debug" и регистр PORTB имеет значение 0x20, что означает, что бит 5 находится в состоянии логической единицы, то есть светодиод в данный момент должен светиться. Смотрю на Arduino - так и есть, светится.

Отправляю команду N.

<3> counters watch

0158 count 2D23 "#-"

015A lcoun 00022D23 "#-.."

0140 text "Debug"

0025 PORTB 00 "."

Регистр PORTB снова равен нулю. Светодиод также погас.

Скачать библиотеку Simple Dumping Monitor

Скачать библиотеку Simple Dumping Monitor можно в разделе Files проекта на сервере SourceForge.

Скачать DumpMon последней версии.

Подробнее о функциях вывода дампов можно прочитать в статье Дамп регистров, памяти, прерываний и таймеров Arduino,

также читайте про Точки останова в обработчиках ISR().

Автор: Андрей Шаройко <vanyamboe@gmail.com>