Для отладки часто используется функция 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 на форуме
Для справки приведу листинг файла retarget.c.
#include <stdio.h> #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.
Перенаправление стандартных потоков ввода-вывода можно сделать в окне Manage Run-Time Environment. Как это делается, показано на картинке.
Пояснения:
Теперь необходимо настроить сам интерфейс ITM, делается это в соответствии со следующей картинкой:
Пояснения:
Важно, чтобы указанная частота в поле Core Clock, совпадала с частотой, на которой будет работать МК в режиме отладки. Если частота будет указана неправильно, внизу экрана Keil будет статус "Trace: Communication Error".
У меня возникла проблема с выводом printf на частоте ядра 8МГц, передача данных не работала, и статус показывал Communication Error. При установке Core Clock = 8МГц, автоматический делитель "Autodetect" выставлялся в 7 и тогда частота SWO Clock становилась не круглой, а именно 1,142857МГц. То есть таким делителем частота 8МГц нацело не делится. При такой дробной частоте понятно, что связь не могла быть установлена. Я пробовал выключить "Autodetect" и поставить другой делитель вручную, но работоспособности трассировки добиться так и не удалось. Отсутствие достаточного количества времени не позволило продолжить эксперименты, вернусь к этому позже. В рабочем же проекте использовалась частота 80МГц, и при этой частоте трассировка работает хорошо, о чем свидетельствует следующая картинка:
Пояснения:
Как видно по картинке, иногда самый первый символ при старте программы пропадает. Видимо требуется какое-то время на синхронизацию интерфейса ITM, после этого все сообщения доходят без потерь.