47480

[i] Printf через ITM

Дата последнего изменения: 29.11.2023 17:08:07
Материал из настоящей статьи, относящийся к микросхеме К1986ВЕ92QI, распространяется в том числе на микроконтроллеры К1986ВЕ92FI, К1986ВЕ92F1I и К1986ВЕ94GI

Для отладки часто используется функция printf(), которая выводит какое-нибудь сообщение или статус, раскрывающий внутреннюю работу программы. Поскольку, в отличие от ПК, в микроконтроллере нет монитора, и стандартный поток вывода STDOUT никуда не привязан, то для того, чтобы функция printf() работала, необходимо указать ей, куда выводить данные. Это реализуется через определение функции fputc(). В этой функции fputc() необходимо реализовать вывод символа char туда, где будут приниматься данные из МК. Чаще всего реализуют вывод сообщений в подключенный UART, от которого сообщения по RS-232 идут в COM-порт ПК и затем отображаются на экране в программе работы с COM-портом (например, PuTTY). Подробнее об этом способе описано в статье Printf через UART.

Однако, в Cortex-M3 и выше есть встроенный серийный порт отладки, который называется ITM (Instrumentation Trace Macrocell). Данные, записываемые в регистры модуля, передаются отладчику по интерфейсу ITM и отображаются на экране в среде разработки. 

В данной статье рассматриваются настройки среды Keil, необходимые для вывода информации через ITM с использованием функции printf(). Для этого можно использовать МК, в которых реализован порт ITM, а именно МК К1986ВЕ92QI и К1901ВЦ1QI (так как в нём использовано RISC-ядро, аналогичное ядру в основе К1986ВЕ92QI). В качестве отладчика могут использоваться CMSIS-DAP, J-LINK, ULINK2.

Интерфейс ITM работает только в SWD ( Serial Wire Debug) режиме отладчика!

Для того чтобы вывести отладочные данные в модуль ITM, обычно к проекту подключается файл типа retarget.c, в котором реализуется функция fputc(), перенаправляющая символ в регистр ITM. 

Листинг файла retarget.c:

#include <stdio.h>
#include "MDR32F9Q2I.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.

Рисунок 1 - Настройка потоков ввода-вывода в Manage Run-Time Environment

Пояснения к рисунку 1.

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

Теперь нужно настроить сам интерфейс ITM, как показано на рисунке 2.

Рисунок 2 - Настройка порта ITM для отладчика J-LINK

Пояснения к рисунку 2.

  1. Открыть настройки проекта.
  2. Открыть вкладку Debug -> Setting (настройки отладчика).
  3. Включить трассировку "Enable" и выставить рабочую частоту ядра "Core Clock".
  4. Установить "Prescaler", чтобы частота "Clock" составляла не более 6 МГц (для J-LINK). 
  5. Оставить включенным один из портов ITM - через него будут передаваться данные.

Важно, чтобы указанная частота в поле "Core Clock" совпадала с частотой, на которой будет работать МК в режиме отладки. Если частота будет указана неправильно, внизу экрана Keil будет статус "Trace: Communication Error". Также не всегда автоматическое определение частоты SWO работает корректно, поэтому рекомендуется установить настройки SWO (Settings SWO) вручную, как показано на рисунке 2. Для J-LINK максимальная частота SWO составляет 6 МГц, для ULINK2 и CMSIS-DAP - 1 МГц.

Теперь переходим к отладке проекта. Последовательность запуска отладки представлена на рисунке 3.

Рисунок 3 - Отладка проекта с использованием вывода информации через ITM

Пояснения к рисунку 3.

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

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

Также, если в конце выводимой строки не указать символ "\n", то строка может быть не выведена сразу в окно "Debug (printf) Viewer".


Сохранить статью в PDF

Теги

Была ли статья полезной?