======Printf через ITM====== Для отладки часто используется функция //printf()//, которая выводит какое-нибудь сообщение или статус, раскрывающий внутреннюю работу программы. Поскольку, в отличие от РС, в микроконтроллере нет монитора, и стандартный поток вывода //stdout// никуда не привязан, то для того чтобы эта функция работала, необходимо указать ей, куда выводить данные. Это реализуется через определение функции //fputc()//. В этой функции //fputc()// необходимо реализовать вывод символа char туда, где будут приниматься данные из МК. Чаще всего реализуют вывод сообщений в подключенный UART, от которого сообщения по RS-232 идут в COM порт РС и затем отображаются на экране в программе работы с COM-портом (например PuTTY ). Но для в Cortex-M3 и выше есть встроенный серийный порт отладки, который называется ITM (Instrumentation Trace Macrocell). Данные, записываемые в регистры модуля, передаются отладчиком по интерфейсу ITM и отображаются на экране в среде разработки. У Миландр порт ITM работает в МК серии 1986ВЕ9х, 1986ВЕ8(81) и 1901ВЦ1Т, поскольку в нем использовано риск ядро от 1986ВЕ9х. Интерфейс ITM работает только в SWD ( Serial Wire Debug) режиме отладчика! Для того чтобы вывести отладочные данные в модуль ITM, обычно к проекту подключается файл типа //retarget.c//, в котором реализуется функция //fputc()//, которая пишет символ в регистр ITM. Демо-пример такой реализации можно найти у **RMax** на [[http://forum.milandr.ru/viewtopic.php?f=33&t=1683&p=17408&hilit=ITM#p7773|форуме]] Для справки приведу листинг файла //retarget.c//. #include #include "MDR32F9x.h" struct __FILE { int handle; }; FILE __stdin, __stdout; volatile int32_t ITM_RxBuffer = 0x5AA55AA5; // Initialize as EMPTY int fgetc(FILE *f) { char tmp; while(ITM_CheckChar() == 0); // Wait if buffer is empty tmp = ITM_ReceiveChar(); if(tmp == 13) tmp = 10; return ITM_SendChar(tmp); } int fputc(int c, FILE *f) { ITM_SendChar(c); return c; } Сами функции //ITM_SendChar, ITM_ReceiveChar, ITM_CheckChar// уже реализованы Keil в файле core_cm3.h, т.е. являются частью функционала ядра. Есть и более простой способ вывести printf через ITM - средствами Keil. =====Вывод Printf через ITM средствами Keil===== Перенаправление стандартных потоков ввода-вывода можно сделать в окне //Manage Run-Time Environment//. Как это делается, показано на картинке. {{prog:debug:Printf_DebugRetarget.png}} Пояснения: - Открываем окно Manage Run-Time Environment - Назначаем поток stdout в порт ITM - При этом в проект автоматически добавляется файл retarget_io.c, реализующий fputc() и прочее. - Для использования printf() необходимо подключить заголовочный файл //stdio.h//. Теперь необходимо настроить сам интерфейс ITM, делается это в соответствии со следующей картинкой: {{prog:debug:printf_trace.png}} Пояснения: - Открываем настройки проекта - Открываем Debug - настройки отладчика (Settings). - Включаем трассировку Trace Enable и выставляем рабочую частоту ядра Core Clock. - Оставляем включенным один из портов ITM, через него пойдут данные. Важно, чтобы указанная частота в поле Core Clock, совпадала с частотой, на которой будет работать МК в режиме отладки. Если частота будет указана неправильно, внизу экрана Keil будет статус //"Trace: Communication Error"//. У меня возникла проблема с выводом printf на частоте ядра 8МГц, передача данных не работала, и статус показывал //Communication Error//. При установке Core Clock = 8МГц, автоматический делитель //"Autodetect"// выставлялся в 7 и тогда частота SWO Clock становилась не круглой, а именно 1,142857МГц. То есть таким делителем частота 8МГц нацело не делится. При такой дробной частоте понятно, что связь не могла быть установлена. Я пробовал выключить //"Autodetect"// и поставить другой делитель вручную, но работоспособности трассировки добиться так и не удалось. Отсутствие достаточного количества времени не позволило продолжить эксперименты, вернусь к этому позже. В рабочем же проекте использовалась частота 80МГц, и при этой частоте трассировка работает хорошо, о чем свидетельствует следующая картинка: {{prog:debug:Printf_DebugShow.png}} Пояснения: - В коде выводим сообщения через printf(). - Заходим в режим отладки, исполнение остановится на входе в main(). - Открываем окно Debug (printf) Viewer. - Запускаем исполнение F5 и в окне Debug (printf) Viewer получаем информацию из printf(). Как видно по картинке, иногда самый первый символ при старте программы пропадает. Видимо требуется какое-то время на синхронизацию интерфейса ITM, после этого все сообщения доходят без потерь.