Инструменты пользователя

Инструменты сайта


prog:debug:printfitm

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 на форуме

Для справки приведу листинг файла 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.

Вывод Printf через ITM средствами Keil

Перенаправление стандартных потоков ввода-вывода можно сделать в окне Manage Run-Time Environment. Как это делается, показано на картинке.

Пояснения:

  1. Открываем окно Manage Run-Time Environment
  2. Назначаем поток stdout в порт ITM
  3. При этом в проект автоматически добавляется файл retarget_io.c, реализующий fputc() и прочее.
  4. Для использования printf() необходимо подключить заголовочный файл stdio.h.

Теперь необходимо настроить сам интерфейс ITM, делается это в соответствии со следующей картинкой:

Пояснения:

  1. Открываем настройки проекта
  2. Открываем Debug - настройки отладчика (Settings).
  3. Включаем трассировку Trace Enable и выставляем рабочую частоту ядра Core Clock.
  4. Оставляем включенным один из портов ITM, через него пойдут данные.

Важно, чтобы указанная частота в поле Core Clock, совпадала с частотой, на которой будет работать МК в режиме отладки. Если частота будет указана неправильно, внизу экрана Keil будет статус "Trace: Communication Error".

У меня возникла проблема с выводом printf на частоте ядра 8МГц, передача данных не работала, и статус показывал Communication Error. При установке Core Clock = 8МГц, автоматический делитель "Autodetect" выставлялся в 7 и тогда частота SWO Clock становилась не круглой, а именно 1,142857МГц. То есть таким делителем частота 8МГц нацело не делится. При такой дробной частоте понятно, что связь не могла быть установлена. Я пробовал выключить "Autodetect" и поставить другой делитель вручную, но работоспособности трассировки добиться так и не удалось. Отсутствие достаточного количества времени не позволило продолжить эксперименты, вернусь к этому позже. В рабочем же проекте использовалась частота 80МГц, и при этой частоте трассировка работает хорошо, о чем свидетельствует следующая картинка:

Пояснения:

  1. В коде выводим сообщения через printf().
  2. Заходим в режим отладки, исполнение остановится на входе в main().
  3. Открываем окно Debug (printf) Viewer.
  4. Запускаем исполнение F5 и в окне Debug (printf) Viewer получаем информацию из printf().

Как видно по картинке, иногда самый первый символ при старте программы пропадает. Видимо требуется какое-то время на синхронизацию интерфейса ITM, после этого все сообщения доходят без потерь.

prog/debug/printfitm.txt · Последнее изменение: 2022/04/03 23:09 (внешнее изменение)