======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, после этого все сообщения доходят без потерь.