Как стать автором
Обновить

Отладка и программирование микроконтроллеров stm32f303, atmega328 через любой интерфейс, как через jtag

Время на прочтение4 мин
Количество просмотров12K
Данная статья посвящена моему первому open source проекту “repl”(ссылка на репозиторий внизу). Идея данного проекта заключается в том, чтоб позволить программисту микроконтроллеров отлаживать программу в микроконтроллере через любой его интерфейс, при этом чтобы отладка не сильно отличалась от отладки через jtag интерфейс. Была возможность остановки программы, установки точек останова, просмотра регистров, памяти, по инструкционной отладки программы.

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

Первая идея для реализации по инструкционной отладки, была сократить время между прерываниями таймера ровно настолько чтоб могла исполниться только 1 инструкция. Данный вариант показал свою идеальную работу на микроконтроллере Atmega328p, дело в том, что минимальное время между прерываниями для Atmega составляет 1 такт процессора, любая инструкция независимо от количества тактов нужного для ее выполнения всегда завершиться если ее выполнение началось.

К сожалению, когда я перешел на stm32, такой вариант не сработал, потому что ядро Cortex-M может прервать исполнение инструкции на середине, а затем по возращению из прерывания начать исполнять ее заново. Тогда я решил хорошо нет проблем просто буду увеличивать количество тактов между прерываниями пока инструкция не исполниться, тут я наткнулся на еще одну проблему некоторые инструкции исполняются только со следующий за ними инструкцией или не исполняются вообще, к сожалению данная проблема не решаемая, поэтому я решил в корне изменить подход.

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

И тут пришла очередь точек останова, для их реализации я решил использовать инструкцию реализующую логику while(1);. Заменяем инструкцию, которая находиться по адресу где хотим поставить точку останова и ждем прерывания таймера. Понимаю, что что-нибудь вроде инструкции, которая вызовет исключение было бы лучше, но хотелось сделать универсальный вариант. При исполнении заменяем данную инструкцию обратно. Хороший вариант если, исполнять программу в оперативной памяти микроконтроллера, в противном случае flash память микроконтроллера долго не проживет. Но к этому моменту я уже закончил писать эмулятор инструкций для stm32 и решил почему бы не написать такой же для Atmega328 и написал. Теперь инструкции заменять обратно не надо их можно эмулировать.

Для того чтоб подружить все это со средой исполнения я сначала хотел, написать свой gdb клиент. К сожалению, он поддерживает два интерфейса для работы с ide. Каким пользоваться ide решает сама. Реализовывать их обоих (первый мне показался довольно простым, второй не очень), плюс пришлось бы совмещать исходники с прошивкой что мне показалось не очень хорошей идеей. Поэтому я решил написать свой gdbserver к счастью протокол был один и он был довольно простой.

Первым моим интерфейсом, который я решил реализовать был GSM. В качестве приемо-передатчика я решил использовать SIM800, в качестве сервера, сервер с поддержкой php. Основная идея заключалась в том, чтоб после прихода post запроса от микроконтроллера держать соединение с микроконтроллером в течении 30 секунд и каждые 100 мс обращаться к базе, если данные появились отсылать их в качестве ответа на запрос и ждать следующего запроса от микроконтроллера.

Первое подключение gdb клиента к серверу, показало, что запросов от gdb клиента серверу слишком много при команде pause или step. Поэтому было решено объединить все эти запросы в один большой для микроконтроллера, для этого я понял логику этих запросов и научился их предсказывать. Теперь данные команды исполнялись не так чтобы быстро, хотелось бы быстрее, но терпимо.

Следующим интерфейсом был usb, для микроконтроллера Atmega328 я решил использовать библиотеку V-usb. Для работы с usb я переписал логику команды run. Теперь микроконтроллер после данной команды не запускал программу ожидая команды pause, он запускал ее на 1 секунду затем на него отправлялась новая команда run и.т.д. Такая логика необходима т.к. я отключаю интерфейс во время работы программы. Для избавления себя от написания драйвера, я решил использовать стандартный hid драйвер. В качестве функций общения hid get feature report, hid set feature report.

Что касается перепрошивки микроконтроллеров, то я решил, что для интерфейса usb это лишнее, так для первой прошивки вам все равно понадобиться программатор. А вот для интерфейса GSM самое оно. Обычно для этой цели пишут отдельную программу, но я решил поступить по-другому, за место написания отдельной программы, я решил загружать программу во flash память микроконтроллера полностью, затем после завершения загрузки копировать данную программу в начало памяти. Затем я подумал зачем мне пересылать программу целиком, я могу переслать только разницу между текущим и предыдущим бинарным файлом прошивки.

Чтоб минимизировать данную разницу, я решил для части программы пользователя переименовать секции .text, .data, .bss, .contructors array(обобщенное название у разных микроконтроллеров разное) и размещать их в памяти сразу после основной программы.

Пришлось также написать свои функции для инициализации данных секций. Теперь в большинстве случаев маленькое изменение программы равно маленькому изменению бинарного файла равно маленькому количеству пересылаемых данных. Как результат часто микроконтроллер перепрошивается быстрее чем работают команды RUN, STEP, PAUSE.

Ну и напоследок видео работы:

Stm32 отладка через usb интерфейс.


Stm32 отладка через gsm интерфейс.


Atmega328 отладка через usb интерфейс.


Atmega328 отладка через gsm интерфейс.


Git repository
Теги:
Хабы:
+11
Комментарии19

Публикации