
Кампания по продвижению нанокомпьютера black swift в самом разгаре (см. также публикацию на habrahabr). black swift построен на базе SoC Atheros AR9331, что позволило сделать его с одной стороны крошечными, недорогим, и малопотребляющим, а с другой стороны в распоряжении пользователя находится процессорное ядро MIPS 24Kc, работающее на частоте до 400 МГц.
Недавно на форуме black-swift.ru был задан вопрос
Есть потребность в документации по использованию JTAG-интерфейса в устройстве. Можно ли ожидать чего-нибудь в этом направлении?
В данной публикации я
Публикация может быть интересна не только разработчикам ПО для AR9331, но и всем интересующимся внутрисхемной отладкой на процессорах с архитектурой MIPS при помощи свободного ПО.
Плат black swift в свободном доступе на момент написания данной публикации ещё нет, однако доступны готовые устройства на базе SoC Atheros AR9331; для демонстрации я буду использовать TP-Link MR3020.
Различие между MR3020 и black swift минимально, более того, освоившему работу с MR3020 переход на black swift может показаться даже облегчением: подключаться к внешним интерфейсам SoC станет проще, а программных препонов меньше.
План демонстрации: мы остановим процессор сразу после старта и запустим на нём вместо штатного зашитого в ПЗУ загрузчика U-Boot другой загрузчик — barebox.
Какую пользу (применительно к MR3020) можно извлечь от использования EJTAG?
- ребята из TP-Link наложили ограничения на внесения изменений в прошивку устройства (хотя, они не очень сильно старались) — возможность использовать EJTAG снимает эти ограничения;
- возможность использовать EJTAG сразу после старта процессора значительно упрощает отладку начальной стадии загрузчика barebox (действительно, использовать EJTAG гораздо комфортнее, нежели возиться с перепрошивкой загрузочного ПЗУ на программаторе);
- EJTAG позволяет восстановить работоспособность устройства после «окирпичивания» в результате порчи содержимого загрузочного ПЗУ.
Чтобы не доходить до уровня изложения «делай раз, делай два, нажми на кнопку — получишь результат» я постараюсь давать минимальные пояснения. Начать стоит с пояснения того, что такое EJTAG.
EJTAG в процессорах с архитектурой MIPS
Без стадии отладки не обходится разработка никакого программного продукта, и счастье программисту, если в его распоряжении имеется толковый отладчик (англ. debugger).
Разработчики ПО для *nix или Windows могут воспользоваться развитыми средствами отладки — можно прогнать свою программу шаг за шагом, посмотреть значения переменных в тот или иной момент времени, поставить точки останова.
Но как быть разработчику ПО для встраиваемой системы? Такое ПО может работать вне окружения какой-либо ОС, а сама встраиваемая система мало похожа на ПК — ни клавиатуры ни монитора как правило нет.
Для того чтобы как-то упростить жизнь в описанной ситуации придумана технология внутрисхемной отладки (англ. in-circuit debugging), которая заключается в следующем: в состав процессора вводится специальный блок (назовём его «блок отладки»), следящий за процессом исполнения инструкций и способный на него повлиять. Этот блок действует не сам по себе, но по командам пользователя (каковым является программист, проводящий отладку ПО). Для внешнего управления этим блоком отладки часто используется интерфейс JTAG.
Почему именно JTAG? JTAG является последовательной шиной (возможно использовать только 4 сигнала), позволяющей соединять десятки устройств (возможно очень разных устройств!) в цепочку, и по мере необходимости передавать команды каждому из устройств. JTAG широко используется для тестирования соединений в печатных платах — в настоящее время БИС любой мало-мальски нетривиальной платы соединены в цепочку JTAG. Вполне резонно использовать JTAG не только для проверки соединений, но и для доставки в процессор команд управления отладкой.
Для процессоров MIPS стандартным является набор аппаратных и программных средств для внутрисхемной отладки под названием EJTAG. EJTAG стандартизирован в документах MIPS EJTAG Specification; существует сразу несколько версий этой спецификации; к примеру в состав процессорного ядра 24Kc входит блок отладки, соответствующий спецификации EJTAG 2.60.
Таким образом не надо смешивать JTAG и EJTAG: JTAG это интерфейс передачи данных; EJTAG — это стандартный для MIPS способ проводить внутрисхемную отладку, при котором используется JTAG.
Что надо для работы с EJTAG?
- Процессор MIPS с поддержкой EJTAG (англ. target или целевой процессор);
- Инструментальная ЭВМ с которой мы будем управлять целевым процессором;
- Устройство, обеспечивающее подключение ЭВМ к интерфейсу JTAG (англ. dongle);
- ПО, которое исполняется на инструментальной ЭВМ, получает от пользователя указания по управлению целевым процессором, и через dongle отправляющее в целевой процессор необходимые команды.
Сразу заметим, что от пользователя не требуются глубокие знания по организации EJTAG, указания по управлению целевым процессором вполне абстрактны, например:
- остановить исполнение инструкций процессором;
- начать исполнение инструкций с адреса такого-то;
- выполнить одну инструкцию и остановиться;
- посмотреть содержимое регистров процессора.
Для нашей демонстрации будем использовать:
- процессор с EJTAG — MIPS 24Kc из состава SoC Atheros AR9331;
- инструментальная ЭВМ — ПК с процессором с архитектурой x86/amd64, работающий под управлением ОС Debian Linux (хотя другие ОС на базе Linux тоже подойдут);
- JTAG dongle — макетная плата с микросхемой FT2232H (а именно microsin.net/adminstuff/hardware/ft2232h-board.html) (далее просто макетка);
- ПО для управления AR9331 через EJTAG —
openocd(http://openocd.sourceforge.net/).
Кроме того, очень желательно подключиться также к интерфейсу UART AR9331, он пригодится для взаимодействия с программами, исполняющимися на процессоре (без подключения к UART демонстрация была бы довольно скучной). Для отправки и приёма символов в UART AR9331 используем программу
minicom.Макетка FT2232H обеспечивает подключение сразу и к UART и к JTAG.
Для взаимодействия с инструментальной ЭВМ будет использоваться интерфейс командной строки, так что готовьте ваши терминалы.
Подключение макетки FT2232H к MR3020
Вот схема подключения (см. также статью на wikidevi.com):

Кому-то такая схема подключения JTAG покажется варварством, но в нашей простой ситуации она вполне оправдана.
Внешний вид MR3020 с подключённой макеткой FT2232H:

Подключение к UART
Вывод интерфейса UART из MR3020 не представляет проблем: на плате уже есть отверстия для впайки штырей.

Обозначения TX и RX на фотографии указаны с точки зрения AR9331, т.е. TX AR9331 (pin 1 на плате) надо подключать к RX FT2232 (BDBUS1).
Рекомендую подключить UART MR3020 к макетке, а саму макетку к инструментальной ЭВМ, и затем, включив питание MR3020, пронаблюдать при помощи
minicom сообщения штатного загрузчика U-Boot.Вот что для этого надо выполнить ряд шагов.
Проверка подключения макетки к инструментальной ЭВМ
Подключить UART MR3020 к макетке; подключить макетку FT2232H к инструментальной ЭВМ по USB; на инструментальной ЭВМ в командной строке запустить dmesg — убедиться, что появились сообщения вроде
[1573965.608101] usb 1-2: new high-speed USB device number 63 using ehci-pci [1573965.740851] usb 1-2: New USB device found, idVendor=0403, idProduct=6010 [1573965.740862] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [1573965.740868] usb 1-2: Product: Dual RS232-HS [1573965.740874] usb 1-2: Manufacturer: FTDI [1573965.741737] ftdi_sio 1-2:1.0: FTDI USB Serial Device converter detected [1573965.741938] usb 1-2: Detected FT2232H [1573965.741948] usb 1-2: Number of endpoints 2 [1573965.741957] usb 1-2: Endpoint 1 MaxPacketSize 512 [1573965.741966] usb 1-2: Endpoint 2 MaxPacketSize 512 [1573965.741974] usb 1-2: Setting MaxPacketSize 512 [1573965.742920] usb 1-2: FTDI USB Serial Device converter now attached to ttyUSB0 [1573965.743493] ftdi_sio 1-2:1.1: FTDI USB Serial Device converter detected [1573965.743662] usb 1-2: Detected FT2232H [1573965.743672] usb 1-2: Number of endpoints 2 [1573965.743681] usb 1-2: Endpoint 1 MaxPacketSize 512 [1573965.743690] usb 1-2: Endpoint 2 MaxPacketSize 512 [1573965.743699] usb 1-2: Setting MaxPacketSize 512 [1573965.744669] usb 1-2: FTDI USB Serial Device converter now attached to ttyUSB1
Из этого сообщения следует, что на инструментальной ЭВМ появились два новых последовательных интерфейса
/dev/ttyUSB0 и /dev/ttyUSB1. В соответствии со схемой подключения к UART MR3020 оказывается подключён второй из двух интерфейсов, то есть /dev/ttyUSB1.Установка и настройка minicom
Установка программы
minicom в основанных на Debian дистрибутивах очень проста:$ sudo apt-get install minicom
Программа
minicom очень добра к новичку — все настройки можно провести через меню, однако эта доброта имеет и обратную сторону — довольно неудобно объяснять как именно выставить необходимые настройки.Чтобы не связываться с системой меню
minicom поступим проще — произведём настройки при помощи конфигурационного файла. Для простоты сделаем глобальный конфигурационный файл, для этого от root'а выполним:# cat <<EOF > /etc/minicom/minirc.USB1 pu port /dev/ttyUSB1 pu baudrate 115200 pu escape-key ^B pu rtscts No EOF
Замечание для пользователей не-Debian дистрибутивов: конфигурационные файлы дляminicomмогут располагаться в месте, отличном от/etc/minicom/.
Указанный конфигурационный файл говорит
minicom'у, что отклонения от настроек по умолчанию заключаются в следующем:- используется порт /dev/ttyUSB1;
- настроить скорость порта 115200;
- клавиша начала команд
minicom— ctrl-b; например, для вызова главного меню надо нажать ctrl-b, затем z; - аппаратное управление потоком отключено (действительно, для подключения мы использовали только линии RX и TX, какое уж там аппаратное управление потоком).
Запуск minicom
Для простоты запустим
minicom от root'а;# minicom USB1
При этом
minicom использует настройки из файла /etc/minicom/minirc.USB1 (если конечно файл ~/.minirc.USB1 не существует).конечно более грамотно добавить своего пользователя в группу dialout...; но давайте не будем усложнять.
Теперь включаем питание MR3020 и наблюдаем в
minicom сообщения от U-Boot:U-Boot 1.1.4 (Aug 17 2012 - 15:21:03) AP121 (ar9330) U-boot DRAM: 32 MB led turning on for 1s... id read 0x100000ff flash size 4194304, sector count = 64 Flash: 4 MB Using default environment
Далее будут выданы сообщения о загрузки linux, но они нам не очень-то и интересны; если какой-то разумный вывод из UART поступает, то можно переходить к подключению JTAG.
Подключение к JTAG
Подключение к JTAG не тривиально, но возможно. См. статью на wikidevi.com.
Кроме четырёх линий JTAG необходимо также обеспечить отключение загрузочного ПЗУ; в статье на wikidevi.com для этого предлагается разрывать линию ChipSelect при помощи перемычки (джампера). Дело в том, что штатный загрузчик U-boot, находящийся в ПЗУ, почти сразу после старта блокирует работу JTAG.
В случае же старта процессора с неработающим ПЗУ ничего страшного не произойдёт, процессор будет вместо программы из ПЗУ выполнять «мусор». Процессор попадёт в сложное положение, но EJTAG останется доступным.
После того, как все линии JTAG оказались соединены с соответствующими выводами FT2232H, а загрузочное ПЗУ отключено, можно попробовать просканировать JTAG-цепочку при помощи
openocd. Но прежде чем запустить openocd, его придётся установить и настроить...Установка программы
openocd не сложнее установки minicom:$ sudo apt-get install openocd
openocd: начальная настройка
В
openocd встроен язык tcl, все сценарии работы и конфигурационные файлы пишутся на нём. Однако для нашего простейшего случая конфигурационный файл будет совсем прост.Создадим файл
ft2232h-scan.cfg, в котором укажем openocd, что будем использовать dongle на базе FT2232H для доступа к JTAG:$ cat <<EOF > ft2232h-scan.cfg interface ftdi ftdi_vid_pid 0x0403 0x6010 ftdi_layout_init 0x0018 0x05fb adapter_khz 100 shutdown EOF
В этом файле мы укажем, что для подключения к JTAG будем использовать «драйвер» ftdi, который и обслуживает все многочисленные dongl'ы на базе FT2232H. Опция ftdi_vid_pid указывает Vendor ID и Device ID микросхемы FT2232H на шине USB (по умолчанию это как раз 0x0403 0x6010; эти ID были в выводе
dmesg, в любой момент их можно просмотреть при помощи программы lsusb). Опция ftdi_layout_init указывает настройки GPIO выходов FT2232H. Опция adapter_khz определяет максимальную частоту тактового сигнала JTAG; 100 КГц (невысокая частота) хорошо подходит для сканирования.Директива shutdown заставит
openocd завершить работу сразу после сканирования JTAG.Давайте запустим
openocd от root'а (Внимание! Запускать openocd следует после включения питания MR3020, причем в момент включения питания должна быть нажата кнопка SW2 на плате MR3020; также не забудьте заблокировать загрузочное ПЗУ):# openocd -f ft2232h-scan.cfg Open On-Chip Debugger 0.8.0 (2014-10-20-22:02) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : only one transport option; autoselect 'jtag' adapter speed: 100 kHz shutdown command invoked Info : clock speed 100 kHz Warn : There are no enabled taps. AUTO PROBING MIGHT NOT WORK!! Warn : AUTO auto0.tap - use "jtag newtap auto0 tap -expected-id 0x00000001 ..." Warn : AUTO auto0.tap - use "... -irlen 5" Warn : gdb services need one or more targets defined
В этом выводе наибольшего внимания заслуживают строчки, содержащие
AUTO auto0.tap — в них приводится информация о найденных абонентах JTAG (tap-контроллерах), причём сразу приводится пример строки которую надо занести в конфигурационный файл openocd для работы со свежеобнаруженным tap-контроллером.Воспользуемся этими строчками и создадим конфигурационный файл для
openocd, который обеспечит загрузку в ОЗУ образа загрузчика barebox.Но прежде чем грузить образ barebox, его надо где-то взять; а так как готовых подходящих образов нигде нет, будет собирать образ самостоятельно из исходных текстов.
Сборка barebox
Образ barebox для AR9331 должен состоять из инструкций процессора MIPS32, а наша инструментальная ЭВМ почти наверняка построена на базе процессора с системой команд x86 или amd64 (так их, во всяком случае, называет Debian).
Для того, чтобы при помощи процессора x86/amd64 породить инструкци�� MIPS32, нам понадобится кросс-компилятор (то есть компилятор, который исполняется на ЭВМ с одной архитектурой команд, а генерирует код для ЭВМ с другой системой команд).
Сборка кросс-компилятора с требуемыми свойствами — задача совсем не тривиальная и для её облегчения создано немало всяких инструментов, известных по ключевым словам buildroot, openwrt, crosstool-ng.
Однако в этой демонстрации мы пойдём простым путём — скачаем готовый кросс-компилятор от MentorGraphics.
Итак, скачиваем и распаковываем в /opt готовый кросс-компилятор:
$ wget http://sourcery.mentor.com/public/gnu_toolchain/mips-linux-gnu/mips-2014.11-22-mips-linux-gnu-i686-pc-linux-gnu.tar.bz2 $ sudo tar fx mips-2014.11-22-mips-linux-gnu-i686-pc-linux-gnu.tar.bz2 -C /opt
В результате, к примеру, путь к кросс-компилятору Си будет таким:
/opt/mips-2014.11/bin/mips-linux-gnu-gcc.Теперь скачаем и распакуем исходные тексты загрузчика barebox:
$ wget http://barebox.org/download/barebox-2015.01.0.tar.bz2 $ tar fx barebox-2015.01.0.tar.bz2
Произведём сборку barebox:
$ cd barebox-2015.01.0 $ make ARCH=mips tplink-mr3020_defconfig $ make ARCH=mips CROSS_COMPILE=/opt/mips-2014.11/bin/mips-linux-gnu- $ cd ..
Если всё прошло хорошо, то получим файл
barebox-2015.01.0/barebox.bin.openocd: более полная настройка
Теперь у нас есть то, что мы можем грузить в ОЗУ MR3020; парадоксально, но у нас нет самого ОЗУ!
Дело в том, что когда для сохранения работоспособности EJTAG мы отключили загрузочное ПЗУ вместе с ним мы отключили начальную инициализацию аппаратуру AR9331, в том числе инициализацию контроллера ОЗУ и контроллера UART.
На наше счастье, последовательность записей в регистры для инициализации аппаратуры уже известна.
Окончательно файл
ft2232h-mr3020.cfg, который обеспечит подключение к блоку отладки AR9331, начальную инициализацию аппаратуры, загрузку образа barebox.bin в ОЗУ MR3020 по адресу 0xa0100000 и запуск его на выполнение выглядит так:interface ftdi ftdi_vid_pid 0x0403 0x6010 ftdi_layout_init 0x0018 0x05fb adapter_khz 600 jtag newtap auto0 tap -expected-id 0x00000001 -irlen 5 target create auto0.tap mips_m4k -endian big -chain-position auto0.tap init halt # pll initialization mww 0xb8050008 0x00018004 mww 0xb8050004 0x00000352 mww 0xb8050000 0x40818000 mww 0xb8050010 0x001003e8 mww 0xb8050000 0x00818000 mww 0xb8050008 0x00008000 sleep 1 # Setup DDR1 config and flash mapping mww 0xb8000000 0x7fbc8cd0 mww 0xb8000004 0x9dd0e6a8 mww 0xb8000010 0x8 mww 0xb8000008 0x133 mww 0xb8000010 0x1 mww 0xb800000c 0x2 mww 0xb8000010 0x2 mww 0xb8000010 0x8 mww 0xb8000008 0x33 mww 0xb8000010 0x1 mww 0xb8000014 0x4186 mww 0xb800001c 0x8 mww 0xb8000020 0x9 mww 0xb8000018 0xff # UART mww 0xb8020004 0x4388 mww 0xb8020008 0xc2000 # GPIO mww 0xb8040028 0x48002 load_image barebox-2015.01.0/barebox.bin 0xa0100000 bin resume 0xa0100000 shutdown
В openocd принята довольно разумная практика, при которой описание dongl'а, описание целевого процессора, а также текущий сценарий отладки принято размещать в разных файлах, но в этой публикации для упрощения изложения мы так поступать не будем.
openocd: загрузка barebox
Итак, загрузим и запустим barebox (Не забудьте про джампер отключения ПЗУ. Также не забывайте держать нажатой кнопку SW2 в момент включения питания MR3020! Наберитесь терпения — загрузка занимает более 100 секунд):
# openocd -f ft2232h-mr3020.cfg Open On-Chip Debugger 0.8.0 (2014-10-20-22:02) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : only one transport option; autoselect 'jtag' adapter speed: 600 kHz Info : clock speed 600 kHz Info : JTAG tap: auto0.tap tap/device found: 0x00000001 (mfg: 0x000, part: 0x0000, ver: 0x0) target state: halted target halted in MIPS32 mode due to debug-request, pc: 0xb0ddd068 Error: No working memory available. Specify -work-area-phys to target. Warn : not enough working area available(requested 128) Error: No working area available Warn : Falling back to non-bulk write 185568 bytes written at address 0xa0100000 downloaded 185568 bytes in 102.970634s (1.760 KiB/s) shutdown command invoked
После окончания работы
openocd в окне minicom мы можем наблюдать сообщения о старте barebox'а:barebox 2015.01.0 #1 Thu Jan 29 02:13:17 MSK 2015 Board: TP-LINK MR3020 m25p80 m25p80@00: unrecognized JEDEC id 900040 m25p80 m25p80@00: probe failed: No such device malloc space: 0xa0400000 -> 0xa07fffff (size 4 MiB) environment load /dev/env0: No such file or directory running /env/bin/init... /env/bin/init not found barebox:/
Далее желающие могут поиграть с командами barebox, список которых откроется по команде help.
Обратите внимание на сообщение об ошибке
probe failed: No such device, оно появилось из-за того, что barebox попытался «нащупать» загрузочное ПЗУ на шине SPI. Но так как для оживления EJTAG загрузочное ПЗУ было отключено, то попытка barebox'а чего-либо найти обречена на неудачу.Если исхитриться надеть перемычку, отключающую загрузочное ПЗУ во время загрузки barebox в память, то можно вместо
m25p80 m25p80@00: unrecognized JEDEC id 900040
наблюдать более оптимистическое
m25p80 m25p80@00: s25sl032p (4096 Kbytes)
Хотя barebox-2015.01.0 поддерживает аппаратуру SoC AR9331 в минимальном объёме (интерфейсы USB и Ethernet не поддерживаются), но прочитать и записать загрузочное ПЗУ barebox'у вполне по силам.
Что дальше? (вместо послесловия)
Загрузка данных в ОЗУ — это не предел возможностей EJTAG. Но нельзя объять необъятное — в публикации не освещены вопросы собственно отладки — этот материал остаётся для будущих публикаций.
Законное негодование вызывает низкая скорость передачи данных — менее 2 Кбайт в секунду, этот момент также надо попытаться исправить.
Благодарности
Автор выражает благодарность людям, без участия которых данная публикация едва ли была бы возможна:
- Алексею Ремпелю, который освоил подключение к JTAG MR3020 и опубликовал свои заметки;
- Алексею Соколову, который совершенно ювелирно припаял провода к резисторам платы моего экземпляра MR3020;
- Петру Мамонову, за разъяснения мне деталей работы EJTAG и различных dongl'ов.