Программирование DSP Blackfin: форматированный вывод в окно терминала через UART Tue, October 08 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

Blackfin: форматированный вывод в окно терминала через UART Печать
Добавил(а) microsin   

В этой статье обсуждается реализация различных функций вывода для семейства Blackfin компании Analog Devices (перевод Engineer-to-Engineer Note EE-347 [1]). Обычно в разных системах программирования это называется перенаправлением вывода printf. Среда разработки VisualDSP++® предоставляет поддержку стандартных C-функций ввода/вывода через такие функции как printf и fprintf. Производительность вывода достаточна для отправки отдельных (не часто повторяющихся) отладочных сообщений в окно Output (консоль терминала) VisualDSP++ IDDE. Однако несколько следующих друг за другом выводов могут повлиять на скорость работы приложения.

Blackfin UART Terminal output putty

Рис. 1. Пример отладочного вывода UART в окно терминала putty.

Все микроконтроллеры семейства Blackfin имеют встроенное периферийное устройство UART (или даже несколько), совместимые по протоколу с индустриальным стандартом компьютеров PC. Вычислительные и аппаратные затраты процессора, необходимые для вывода через UART, довольно малы. В принципе для отладочного вывода достаточно только одной сигнальной ножки процессора (сигнал передачи TXD). Скорость работы ядра вполне достаточна, чтобы быстро отправить в консоль одиночное отладочное сообщение, не оказывая влияния на общую реальную производительность приложения.

В этом руководстве предлагается 3 разных способа реализовать мощную систему отладки, которая сохраняет вид и принципы стандартного I/O на языке C. Для доступных в настоящий момент плат разработчика Blackfin есть примеры кода [2]. 3 метода описаны в следующих секциях:

• Прямой программный доступ к UART
• Замена стандартного устройства
• Расширение поддержки ввода/вывода для новых устройств

Дополнительную информацию по программированию см. в документации [3, 10].

Все описанные методы требуют корректной настройки интерфейса UART процессора Blackfin. В примерах для этой цели предоставлены функции, реализация которых привязана к модели процессора. Эти функции можно найти в файлах ADSP-BF5xx-UART.c и ADSP-BF60x-UART.c. Функции в этих файлах используются для инициализации портов Blackfin, периферийного устройства UART и отправки через UART содержимого буфера в памяти. Связанные файлы заголовков (наподобие ADSP-BF5xxUART.h) содержат информацию по выбранному номеру UART, каналу DMA, и задают, используется ли детектирование скорости передачи, или скорость задается жестко на этапе компиляции. Есть еще файлы кода BfDebugger.c и BfDebugger.h, их функции описываются в следующих секциях.

[Прямой программный доступ к UART]

Первый метод непосредственного доступа к UART базируется на использовании макросов препроцессора и библиотеки обработки строк (string.h), чтобы сгенерировать содержимое форматированной строки для отправки через UART. Для вывода через UART создаются отдельные, специальные функции, которые выглядят похоже на стандартную функцию printf, и используются точно так же.

Функции можно найти в файлах BfDebugger.c и BfDebugger.h, используются следующие прототипы:

short udprintf(unsigned char UartNum,
               unsigned char DmaChan,
               const char *format,
               /* аргументы */ ...);
 
short uprintf(unsigned char UartNum,
              const char *format,
              /* аргументы */ ...);

Имена функций и их аргументы выглядят очень похоже на стандартную функцию наподобие printf, которая принимает список переменных в аргументах. В аргументе format задается, как обычно, стандартный набор спецификаторов и директив форматирования (описание см. например, в [4]) и обычные символы текста, что управляет генерацией данных для вывода. Примеры использования:

udprintf(0,9,"Hello UART%d\n",0);
uprintf(0,"Hello UART%d\n",0);

Как Вы уже наверное догадались, в параметре UartNum указывается номер используемого порта UART, а в параметре DmaChan указывается номер канала DMA. Возврат каретки \r и завершающий строку нулевой символ (как принято для ASCIIZ-строк на языке C) вставляются автоматически. Функция вернет количество успешно переданных символов, или отрицательное число, если произошла ошибка.

Определения для препроцессора (Preprocessor Definitions). Чтобы помочь программисту гибкой поддержкой функций uprintf в отличие от обычных функций printf, есть набор опций препроцессора, позволяющие переключаться между различными режимами. Можно использовать только одну опцию из следующих, по выбору:

• __DEBUG_UART_DMA__ прямой вывод в UART, режим DMA
• __DEBUG_UART__ прямой вывод в UART, режим вывода с участием ядра
• __DEBUG_FILE__ прямой вывод в файл
• __DEBUG_VDSP__ прямой вывод в окно Output среды VisualDSP++ (консоль терминала)

Последние 2 опции из этого списка дают дополнительную возможность вывода данных в файл, как при использовании стандартной функции fprintf().

• __VERBOSITY__ [int] Уровень подробности (Level of verbosity, LoV).

Это определение позволяет маскировать (т. е. отключать) или демаскировать (т. е. разрешать) отдельные сообщения с использованием их уровня иерархии. Так, например, если __VERBOSITY__ задано как 2, то любые сообщения, использующие макрос препроцессора (будет рассмотрено в следующей секции), где n установлено в 1 или 2 (DEBUG(1, args) или DEBUG(2, args)) будут напечатаны, однако для n == 3 (DEBUG(3, args)) или более высокого уровня сообщения будут замаскированы (т. е. не будут напечатаны).

Макросы препроцессора. Набор макросов препроцессора добавляет дополнительный функционал, такой как вычисление требуемого уровня LoV и автоматическая раскраска вывода разными цветами. Макросы вставляют, в соответствии с файлом ADSP-BF5xx-UART.h, правильные номера для UART и канала DMA.

• DEBUG(n, *format, /* аргументы */ ...) вывод без окраски, отладочные сообщения
• INFO(n, *format, /* аргументы */ ...) желтый текст, информационные сообщения
• ERROR(n, *format, /* аргументы */ ...) красный текст, сообщения об ошибке
• MSG(n, *format, /* аргументы */ ...) зеленый текст, сообщения для пользователя

Для раскраски выводимых символов используются специальные стандартные управляющие ESC-коды (ANSI escape sequences, их коды можно найти в [5]).

И наконец, есть макросы DEBUG_OPEN() и DEBUG_CLOSE(), которые требуется в приложении использовать обычно только по одному разу каждый (если используются несколько раз, то их нужно применять попарно), которые подготавливают и закрывают все требуемые для вывода ресурсы, включая настройку UART.

DEBUG_OPEN();
DEBUG(1,"Hello UART%d\n",0);
ERROR(1,"Это сообщение об ошибке\n");
DEBUG_CLOSE();

[Стандартная библиотека ввода вывода C/C++]

В этом разделе рассматриваются функции стандартной библиотеки ввода вывода C/C++ (C/C++ Run-Time I/O Library, CRT), которые можно использовать для отправки отладочной информации из приложения. Дополнительные примеры использования можно найти по ссылкам [6] и [7].

stdio.h. Заголовочный файл stdio.h определяет набор функций библиотеки, макросы и типы данных, применяемые для ввода и вывода. Стандартные функции для генерирования форматированного вывода относятся к семейству функций printf. Функция printf посылает преобразованные данные своих аргументов с в стандартный поток stdout, который по умолчанию в среде разработки VisualDSP++ соответствует окну консоли Output. Программист может поменять устройство вывода или файл, на который ссылается поток stdout. Функция fprintf записывает данные в указатель на файл (file-pointer). Связанный с выводом файл открывается / закрывается на PC функциями fopen / fclose.

Поддержка файлового ввода/вывода. File I/O подробно описан в [3, 10]. По умолчанию стандартный функционал языка C достигается через так называемое устройство PrimIO. Оно настраивается и регистрируется при запуске библиотекой CRT, и обрабатывает три стандартных файла - стандартные потоки stdin, stdout и stderr, и любые другие потоки, открытые пользователем, если устройство по умолчанию не изменено.

[Замена стандартного устройства]

Этот метод относится к радикальным. Любой вызов printf будет, как обычно, отформатирован подсистемой ввода/вывода, однако направлен в функцию _write (см. структуру DevEntry, которая определена в заголовочном файле device.h), связанной с Вашим новым устройством. Недостатком этого метода будет то, что Вы потеряете отдельную функциональность вывода в отладочную консоль. Достоинство метода в том, что существующие исходные файлы кода, использующие вывод, останутся не измененными, требуется добавить в проект только несколько дополнений. Изменения должны быть внесены в модули devtab.c и primiolib.c. Эти файлы уже подготовлены и предоставлены в коде проектов примеров [2].

Модификация devtab.c требуется в том случае, если устройство должно быть предварительно зарегистрировано, когда настраивается CRT. Если новое устройство требует стандартных потоков вместо устройства PrimIO device, то нужно модифицировать модуль primiolib.c.

Файл BfDebugger.c определяет устройство с требуемыми указателями на функцию:

struct DevEntry UartIODevice

Заголовочный файл BfDebugger.h предоставляет определения препроцессора, используемые для активации замещающих методов:

• __UART_IO_DEVICE__
• __PRE_REGISTERING_DEVICE__

Следующие определения задают, как будет использоваться UART - ядром или через DMA. Можно выбрать один из 2 вариантов:

• __DEBUG_UART_DMA__
• __DEBUG_UART__

После этого любой вывод с помощью функции printf будет перенаправлен в заданное периферийное устройство UART.

[Расширение поддержки ввода/вывода для новых устройств]

Этот последний метод более элегантен, чем предыдущий. Он также использует возможность расширить поддержку I/O для новых устройств. Но теперь стандартный функционал вывода сохраняется.

Используются те же самые файлы исходного кода, что и в предыдущем примере. Предварительная регистрация устройства не выполняется.

int PrimDevId = get_default_io_device();
int SecDevId = add_devtab_entry(&UartIODevice);
 
set_default_io_device(SecDevId);
pUartIOFile = fopen("uart","w");
if(setvbuf(pUartIOFile,buf,_IOLBF,size of(buf)) == -1)
{
   return -1;
}
 
set_default_io_device(PrimDevId);
fprintf(pUartIOFile,"Test\n");
printf("Test\n");
fclose(pUartIOFile);

В этом примере кода сохраняется текущий идентификатор устройства (PrimDevId). Затем добавляется новое устройство (UartIODevice), и помечается как устройство по умолчанию (default device). Операция fopen открывает псевдо-файл на устройстве по умолчанию. Сразу после этого нужно связать новый буфер с новым устройством. Для консольного вывода предпочтительно использовать буфер для строки. Предыдущее устройство по умолчанию можно восстановить, и запись может быть выполнена в новое устройство. Вывод printf все еще можно увидеть в окне Output среды разработки VisualDSP++.

SDTIO System Service. Системные службы (System Services), интегрированные начиная с VisualDSP++ Update 8, предоставляют похожий метод для перенаправления printf в UART. Примеры можно найти в папке, относящейся к отдельной плате разработчика (Evaluation Board examples):

\Services\stdio\char_echo\

[Отличия метода прямой работы с UART и метода использования устройства ввода/вывода]

Обратной стороной использования устройства ввода/вывода, в отличие от прямой работы с UART, является режим DMA. Перед обновлением буфера сначала должна быть завершена текущая выполняющаяся передача DMA. Это гарантируется функцией UartDmaWaitForDmaDone.

Поскольку система I/O подготавливает буфер на самом первом этапе, нужен опрос бита DMA_DONE (флаг, сигнализирующий о завершении DMA) сразу после начала передачи. Прямая работа с UART позволяет переместить подпрограмму ожидания перед подготовкой передаваемого буфера.

[Консольное приложение]

На рис. 1 в начале статьи показан пример вывода в окно терминала PuTTY (популярная консольная утилита Windows). Эта программа может использоваться как хорошая альтернатива терминальной программы, потому что стандартный HyperTerminal® был удален из Windows Vista®. Окно PuTTY должно быть настроено для вывода как минимум 91 столбцов текста (т. е. столько символов должно поместиться в одной строке терминала), чтобы корректно отобразилось сообщение, показанное на рисунке.

[Поддержка CrossCore Embedded Studio®]

Этот документ, и особенно прилагаемый ZIP-файл с исходным кодом [2] был обновлен для поддержки новых моделей процессоров семейства Blackfin, ADSP-BF60x. Эти процессоры поддерживаются только новой средой разработки CrossCore Embedded Studio®. Добавлен проект, работающий на двухядерном процессоре платы разработчика ADSP-BF609 ET-KIT Lite® Evaluation Board.

I.   ФУНКЦИОНАЛЬНОЕ ОПИСАНИЕ

Каталог содержит примеры перенаправления вывода функции printf на разные устройства вывода. В этом случае задейстовано периферийное устройство UART процессора Blackfin (или файл на Вашем компьютере PC).

Для всех платформ отладки процессора Blackfin доступны отдельные проекты.

Все примеры кода ADSP-BF5xx были разработаны с использованием:

- отладочных плат разработчика Blackfin EZ-KIT
- VisualDSP++ 5.0 Update 10

Все примеры кода ADSP-BF6xx были разработаны и протестированы с использованием:

- отладочных плат разработчика Blackfin EZ-KIT
- CrossCore Embedded Studio 1.0.1

II.  ОПИСАНИЕ РАБОТЫ

Пожалуйста тщательно прочитайте апноут EE-347 вместе с комментариями в исходном коде. Требуемые настройки для переключения между разными поддерживаемыми режимами задаются определениями в файле BfDebugger.h. Вот эти определения (подробнее см. заголовочный файл Common Code\BfDebugger.h):

Макроопределение Описание
__UART_IO_DEVICE__ Если эта опция определена как 1, то в качестве системного устройства вывода будет использоваться UART.
__PRE_REGISTERING_DEVICE__ Если 1, то задана предрегистрация устройства: это заменяет устройство PrimIO для stdin, stdout и stderr.
__DEBUG_UART__ Если 1, то печать направляется в UART под управлением ядра (без DMA).
__DEBUG_UART_DMA__ Если 1 (задано по умолчанию), то печать направляется в UART под управлением DMA.
__DEBUG_FILE__ Если 1, то печать направляется в файл DEBUG_FILE_NAME.
__DEBUG_VDSP__ Если 1, то печать направляется в окно консоли среды разработки VisualDSP (этот вариант вывода самый медленный!!!).
__VERBOSITY__ Уровень подробности вывода (по умолчанию задано как 2). В макросах первым параметром передается число уровня подробности вывода (например, DEBUG(2, "Hello World")). Если это число больше или равно установке __VERBOSITY__, то вывод сработает, иначе ничего не будет выведено.

Больше ничего вообще не должно быть изменено.

III. НАСТРОЙКИ АППАРАТУРЫ

Номер выбранного порта UART по умолчанию установлен в соответствии с имеющимися коннекторами на отладочной плате. Также поддерживается автодетект скорости. Настройки UART по умолчанию следующие (их можно поменять в специальном файле заголовка ADSP-BF5xx-UART.h):

Скорость (bitrate): 115200
Дина слова: 8 бит
Количество стоп-битов: 1
Нет контроля четности (No parity)
Нет управления потоком (No flow control)

Длина слова (количество бит во фрейме RS-232) может быть изменено определением UART_LCR_VAL.

Установки переключателей/перемычек должны быть по умолчанию.

IV.  КАКИЕ ФАЙЛЫ СОДЕРЖАТСЯ В ЭТОМ КАТАЛОГЕ

[BfUart]
|
|-> README.txt
|
|- [Common Code]
   |
   |-> BfDebugger.c
   |-> BfDebugger.h
   |-> devtab.c
   |-> init_platform.h
   |-> main.c
   |-> nBlackfin.h
   |-> NOR_FLASH.c
   |-> NOR_FLASH.h
   |-> primiolib.c
   |-> system.c
   |-> system.h
   |-> TWI.c
   |-> TWI.h
   |-> VR_DIGIPOT.c
   |-> VR_DIGIPOT.h
|
|- [ADSP-BF50x-UART]
   |
   |-> ADSP-BF50x-UART.c
   |-> ADSP-BF50x-UART.dpj
   |-> ADSP-BF50x-UART.h
   |-> ADSP-BF50x-UART.ldf
   |-> ADSP-BF50x-UART_basiccrt.s
   |-> ADSP-BF50x-UART_heaptab.c
   |-> ezkitBF506f_initcode.h
|
|- [ADSP-BF51x-UART]
   |
   |-> ADSP-BF51x-UART.c
   |-> ADSP-BF51x-UART.dpj
   |-> ADSP-BF51x-UART.h
   |-> ADSP-BF51x-UART.ldf
   |-> ADSP-BF51x-UART_basiccrt.s
   |-> ADSP-BF51x-UART_heaptab.c
   |-> ezboardBF518f_initcode.h
|
|- [ADSP-BF526_FAMILY-UART]
   |
   |-> ADSP-BF52x-UART.c
   |-> ADSP-BF52x-UART.dpj
   |-> ADSP-BF52x-UART.h
   |-> ADSP-BF526-UART.ldf
   |-> ADSP-BF526-UART_basiccrt.s
   |-> ADSP-BF526-UART_heaptab.c
   |-> ezboardBF526_initcode.h
|
|- [ADSP-BF527_FAMILY-UART]
   |
   |-> ADSP-BF52x-UART.c
   |-> ADSP-BF527-UART.dpj
   |-> ADSP-BF52x-UART.h
   |-> ADSP-BF527-UART.ldf
   |-> ADSP-BF527-UART_basiccrt.s
   |-> ADSP-BF527-UART_heaptab.c
   |-> ezkitBF527_initcode.h
|
|- [ADSP-BF533_FAMILY-UART]
   |
   |-> ADSP-BF532-UART.c
   |-> ADSP-BF533_FAMILY-UART.dpj
   |-> ADSP-BF532-UART.h
   |-> ADSP-BF533_FAMILY-UART.ldf
   |-> ADSP-BF533_FAMILY-UART_basiccrt.s
   |-> ADSP-BF533_FAMILY-UART_heaptab.c
   |-> ezkitBF533_initcode.h
|
|- [ADSP-BF537_FAMILY-UART]
   |
   |-> ADSP-BF534-UART.c
   |-> ADSP-BF537_FAMILY-UART.dpj
   |-> ADSP-BF534-UART.h
   |-> ADSP-BF537_FAMILY-UART.ldf
   |-> ADSP-BF537_FAMILY-UART_basiccrt.s
   |-> ADSP-BF537_FAMILY-UART_heaptab.c
   |-> ezkitBF533_initcode.h
|
|- [ADSP-BF538_FAMILY-UART]
   |
   |-> ADSP-BF538-UART.c
   |-> ADSP-BF538_FAMILY-UART.dpj
   |-> ADSP-BF538-UART.h
   |-> ADSP-BF538_FAMILY-UART.ldf
   |-> ADSP-BF538_FAMILY-UART_basiccrt.s
   |-> ADSP-BF538_FAMILY-UART_heaptab.c
   |-> ezkitBF538f_initcode.h
|
|- [ADSP-BF54x-UART]
   |
   |-> ADSP-BF54x-UART.c
   |-> ADSP-BF54x-UART.dpj
   |-> ADSP-BF54x-UART.h
   |-> ADSP-BF54x-UART.ldf
   |-> ADSP-BF54x-UART_basiccrt.s
   |-> ADSP-BF54x-UART_heaptab.c
   |-> ezkitBF548_initcode.h
|
|- [ADSP-BF561-UART]
   |
   |-> ADSP-BF561-UART.c
   |-> ADSP-BF561-UART.dpj
   |-> ADSP-BF561-UART.h
   |-> ADSP-BF561-UART.ldf
   |-> ADSP-BF561-UART_basiccrt.s
   |-> ADSP-BF561-UART_heaptab.c
   |-> ezkitBF561_initcode.h
|
|- [ADSP-BF59x-UART]
   |
   |-> ADSP-BF59x-UART.c
   |-> ADSP-BF59x-UART.dpj
   |-> ADSP-BF59x-UART.h
   |-> ADSP-BF59x-UART.ldf
   |-> ADSP-BF59x-UART_basiccrt.s
   |-> ADSP-BF59x-UART_heaptab.c
   |-> ezkitBF592_initcode.h
|
|- [ADSP-BF60x-UART]
   |
   |- [.settings]
   |-> [...]
   |- [src]
   |-> [...]
   |- [system]
   |-> [...]
|- [ADSP-BF60x-UART_Core1]
   |
   |- [.settings]
   |-> [...]
   |- [src]
   |-> [...]
   |- [system]
   |-> [...]

Модули, не привязанные к архитектуре (к типу процессора), находятся в папке Common Code. Среди этих файлов самый важный для пользователя файл Common Code\BfDebugger.h (см. врезку ниже). В нем конфигурируется, как будет вести себя вывод через UART (см. макроопределения __DEBUG_UART__, __DEBUG_UART_DMA__, __DEBUG_FILE__, __DEBUG_VDSP__). В файле Common Code\main.c приведен простейший пример кода использования библиотеки вывода.

Этот конфигурационный файл задает основное поведение библиотеки вывода. Поменяйте в нем установки __DEBUG_UART__, __DEBUG_UART_DMA__, __DEBUG_FILE__, __DEBUG_VDSP__, __VERBOSITY__, чтобы они соответствовали Вашим потребностям.

/*****************************************************************************
**                                                                          **
**  BfDebugger                                                              **
**                                                                          **
******************************************************************************
(C) Copyright 2009-2012 - Analog Devices, Inc.  All rights reserved.
 
Файл: BfDebugger.h
Дата модификации: 03/29/2012
Процессор: Blackfin
Среда разработки: VisualDSP++ 5.0
 
Этот заголовочный файл подключает необходимые специфичные для цели файлы *UART.h
(например файл ADSP-BF538-UART.h), в зависимости от предварительно заданных целевых
макросов препроцессора (т. е. настроек типа процессора, заданных в проекте). Эти
файлы *UART.h содержат индивидуальные настройки для компилируемой цели (под целью
подразумевается тип процессора Blackfin).
 
Этот файл заголовка предоставляет некоторые удобные для использования макросы
препроцессора для управления подробностями вывода (__VERBOSITY__) и цветом
печатаемого текста в консоли (DEBUG=по умолчанию серый, INFO=зеленый, WARNING=желтый,
ERROR=красный, MSG=белый) в том случае, если используется вывод в консоль терминала
через UART.
 
Макрос CONTROL не вставляет никакие дополнительные управляющие последовательности
наподобие новой строки (LF) или возврата каретки (CR). Пример синтаксиса: DEBUG(LoV, arg...);
 
Когда используются макросы, приложение может переключаться между выводом текста
на основе printf, fprintf, uprintf и udprintf.
 
Управляющие коды ANSI передаются стандартно, с использованием префикса из escape-символа (ESC,
код ASCII 27), за которым следует нужная последовательность управляющего кода:
 
Код:            Значение:
\a              Alert (звуковое предупреждение)
\b              Backspace (возврат печати на 1 позицию назад)
\f              Form Feed (перевод страницы)
\n              Newline (новая строка)
\r              Carriage Return (возврат каретки)
\t              Horizontal Tab (горизонтальная табуляция)
\v              Vertical Tab (вертикальная табуляция)
 
[0m             сброс; очищает все цвета и стили (белый текст на черном фоне)
[1m             bold on (включение жирного шрифта, см. ниже)
[3m             italics on (включение наклонного шрифта)
[4m             underline on (включение подчеркивания)
[7m             inverse on (включение инверсии); меняет местами цвета текста и фона
                (foreground & background colors)
[9m             strikethrough on (включение зачеркивания)
[22m            bold off (выключение жирного шрифта, см. ниже)
[23m            italics off (выключение наклонного шрифта)
[24m            underline off (выключение подчеркивания)
[27m            inverse off (выключение инверсии)
[29m            strikethrough off (выключение зачеркивания)
[30m            set foreground color to black (установка текста в черный цвет)
[31m            set foreground color to red (установка текста в красный цвет)
[32m            set foreground color to green (установка текста в зеленый цвет)
[33m            set foreground color to yellow (установка текста в желтый цвет)
[34m            set foreground color to blue (установка текста в синий цвет)
[35m            set foreground color to magenta (purple, установка текста в пурпурный цвет)
[36m            set foreground color to cyan (установка текста в голубой цвет)
[37m            set foreground color to white (установка текста в белый цвет)
[39m            set foreground color to default (установка текста в цвет по умолчанию, белый)
[40m            set background color to black (установка фона в черный цвет)
[41m            set background color to red (установка фона в красный цвет)
[42m            set background color to green (установка фона в зеленый цвет)
[43m            set background color to yellow (установка фона в желтый цвет)
[44m            set background color to blue (установка фона в синий цвет)
[45m            set background color to magenta (purple, установка фона в пурпурный цвет)
[46m            set background color to cyan (установка фона в голубой цвет)
[47m            set background color to white (установка фона в белый цвет)
[49m            set background color to default (установка фона в цвет по умолчанию, черный)
******************************************************************************/
 
#ifndef __DEBUG_H__
#define __DEBUG_H__
 
/*******************************************************************************
*
*  Экспортируемые константы/определения: их может менять пользователь
*
*******************************************************************************/
 
//#define __UART_IO_DEVICE__          1   // Расширение поддержки I/O для нового устройства: Uart
//#define __PRE_REGISTERING_DEVICE__  1   // Предрегистрация устройства: это заменяет устройство PrimIO
                                          //  для stdin, stdout и stderr
 
 
//Если задано несколько определений сразу, то в результате получится, что активно только
// определение __DEBUG_UART__, при этом не будет выдано предупреждений.
//#define __DEBUG_UART__              1   // печать направляется в UART (режим ядра, без DMA)
#define __DEBUG_UART_DMA__          1   // печать направляется в UART (режим DMA)
//#define __DEBUG_FILE__              1   // печать направляется в файл DEBUG_FILE_NAME
//#define __DEBUG_VDSP__              1   // печать направляется в окно консоли среды разработки VisualDSP
                                        // (этот вариант вывода самый медленный!!!)
 
// Уровень подробностей вывода
#define __VERBOSITY__               2
 
/*******************************************************************************
*
*  Экспортируемые константы/определения: их менять не следует
*
*******************************************************************************/
 
// некая предварительная проверка синтаксиса
#if ( (__DEBUG_UART_DMA__ == 0) && (__DEBUG_UART__ == 0) && (__DEBUG_FILE__ == 0) && (__DEBUG_VDSP__ == 0) )
    #warning "__DEBUG_UART_DMA__" is enabled automatically
    #define __DEBUG_UART_DMA__  1
#endif
 
#if ( (__PRE_REGISTERING_DEVICE__ == 1) && (__UART_IO_DEVICE__ == 0) )
    #warning "__UART_IO_DEVICE__" is enabled automatically
    #undef __UART_IO_DEVICE__
    #define __UART_IO_DEVICE__  1
#endif
 
#if ( (__UART_IO_DEVICE__ == 1) && (__DEBUG_UART_DMA__ == 0) && (__DEBUG_UART__ == 0) )
    #warning "__DEBUG_UART_DMA__" is enabled automatically "__DEBUG_VDSP__" and/or "__DEBUG_FILE__" have been removed
    #undef __DEBUG_FILE__
    #undef __DEBUG_VDSP__
    #undef __DEBUG_UART__
    #define __DEBUG_UART_DMA__  1
#endif
 
#define STRINGSIZE 512
 
#if ( (__DEBUG_UART_DMA__ == 1) || (__DEBUG_UART__ == 1) )
    #define _PROMPT_        "bf\\>"
    #define _RESETSCREEN_   "\f\e[0m"
    #define _CLEARSCREEN_   "\e[2J"
    #define _ERASELINE_     "\e[K"
//    #define _NEWLINE_       "\n\r" // возврат каретки вставляется автоматически
    #define _NEWLINE_       "\n"
    #define _CARRIAGE_      "\r"
    #define _VTAB_          "\v"
    #define _HTAB_          "\t"
    #define _CURSORUP_      "\e[A"
    #define _CURSORDN_      "\e[B"
    #define _CURSORFW_      "\e[C"
    #define _CURSORBW_      "\e[D"
    #define _CURSORUPX_     "\e[%dA" // требует количество строк в первом параметре
    #define _CURSORDNX_     "\e[%dB" // требует количество строк в первом параметре
    #define _CURSORFWX_     "\e[%dC" // требует количество строк в первом параметре
    #define _CURSORBWX_     "\e[%dD" // требует количество строк в первом параметре
    #define _CURSORPOSXY_   "\e[%d;%dH"
    #define _CURSORPOSSAVE_ "\e[s"
    #define _CURSORPOSREST_ "\e[u"
    #define _INVERSEON_     "\e[7m"
    #define _INVERSEOFF_    "\e[27m"
    #define _NORMALTEXT_    "\e[0m"
    #define _BOLDTEXT_      "\e[1m"
    #define _ITALICTEXT_    "\e[3m"
    #define _BLINKTEXT_     "\e[5m"
    #define _REDTEXT_       "\e[31m"
    #define _GREENTEXT_     "\e[32m"
    #define _YELLOWTEXT_    "\e[33m"
    #define _BLUETEXT_      "\e[34m"
    #define _MAGENTATEXT_   "\e[35m"
    #define _CYANTEXT_      "\e[36m"
    #define _WHITETEXT_     "\e[37m"
    #define _BLACKTEXT_     "\e[30m"
    #define _TEST_          "\e[=3h"
#else
    #define _PROMPT_        ""
    #define _RESETSCREEN_   "\n"
    #define _CLEARSCREEN_   "\n"
    #define _ERASELINE_     ""
    #define _NEWLINE_       "\n"
    #define _CARRIAGE_      "\r"
    #define _VTAB_          "\n"
    #define _HTAB_          "\h"
    #define _CURSORUP_      ""
    #define _CURSORDN_      ""
    #define _CURSORFW_      ""
    #define _CURSORBW_      ""
    #define _CURSORUPX_     ""
    #define _CURSORDNX_     ""
    #define _CURSORFWX_     ""
    #define _CURSORBWX_     ""
    #define _CURSORPOSXY_   ""
    #define _CURSORPOSSAVE_ ""
    #define _CURSORPOSREST_ ""
    #define _INVERSEON_     ""
    #define _INVERSEOFF_    ""
    #define _NORMALTEXT_    ""
    #define _BOLDTEXT_      ""
    #define _ITALICTEXT_    ""
    #define _BLINKTEXT_     ""
    #define _REDTEXT_       ""
    #define _GREENTEXT_     ""
    #define _YELLOWTEXT_    ""
    #define _BLUETEXT_      ""
    #define _MAGENTATEXT_   ""
    #define _CYANTEXT_      ""
    #define _WHITETEXT_     ""
    #define _BLACKTEXT_     ""
    #define _TEST_          ""
#endif
#define _NL_    _NEWLINE_
#define _CR_    _CARRIAGE_
#define _EL_    _ERASELINE_
#define _CS_    _CLEARSCREEN_
 
static char crsuw[] = { '\e', '[', 'A' }; // Курсор вверх
static char crsdw[] = { '\e', '[', 'B' }; // Курсор вниз
static char crsfw[] = { '\e', '[', 'C' }; // Курсор вперед
static char crsbw[] = { '\e', '[', 'D' }; // Курсор назад
 
static char crstb[] = { '\e', '[', '4', 'C' }; // Tab: курсор вперед на 4 позиции
 
/*******************************************************************************
*
*  Область подключения заголовочных файлов
*
*******************************************************************************/
#if ( (__DEBUG_UART_DMA__ == 1) || (__DEBUG_UART__ == 1) )
    #if (__ADSPBF50x__ == 1)
        #include "ADSP-BF50x-UART.h"
    #elif (__ADSPBF51x__ == 1)
        #include "ADSP-BF51x-UART.h"
    #elif (__ADSPBF52x__ == 1)
        #include "ADSP-BF52x-UART.h"
    #elif (__ADSPBF533_FAMILY__ == 1)
        #include "ADSP-BF532-UART.h"
    #elif (__ADSPBF537_FAMILY__ == 1)
        #include "ADSP-BF534-UART.h"
    #elif (__ADSPBF538_FAMILY__ == 1)
        #include "ADSP-BF538-UART.h"
    #elif (__ADSPBF54x__ == 1)
        #include "ADSP-BF54x-UART.h"
    #elif (__ADSPBF561__ == 1)
        #include "ADSP-BF561-UART.h"
    #elif (__ADSPBF59x__ == 1)
        #include "ADSP-BF59x-UART.h"
    #else
        #error target not supported
    #endif
#endif // (__DEBUG_UART_DMA__ == 1) || (__DEBUG_DMA__ == 1)
 
/*******************************************************************************
*
*  Область экспортируемых типов
*
*******************************************************************************/
 
/*******************************************************************************
*
*  Область экспортируемых макросов
*
*******************************************************************************/
 
/* Доступные макросы:
DEBUG_OPEN()
DEBUG_CLOSE()
CONTROL(< level of verbosity >, args...)
DEBUG(< level of verbosity >, args...)
MSG(< level of verbosity >, args...)
INFO(< level of verbosity >, args...)
WARNING(< level of verbosity >, args...)
ERROR(< level of verbosity >, args...)*/
 
#if (__DEBUG_UART__ == 1)
 
#undef __DEBUG_FILE__
#undef __DEBUG_VDSP__
#undef __DEBUG_UART_DMA__
 
#if (AUTOBAUD == 0)
#define DEBUG_OPEN()    UartInitTerminal(USE_UART_NR,USE_UART_BITRATE)
#else
#define DEBUG_OPEN()    UartInitAutobaud(USE_UART_NR)
#endif
#define DEBUG_CLOSE()   UartClockDisable(USE_UART_NR)
 
 
#if (__VERBOSITY__ > 0)
#define CONTROL(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) { uprintf(USE_UART_NR, args); }\
    } while (0)
#else
#define CONTROL(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define DEBUG(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) { uprintf(USE_UART_NR,_NORMALTEXT_ _CR_ args); }\
    } while (0)
#else
#define DEBUG(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define INFO(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) {\
        uprintf(USE_UART_NR,_BOLDTEXT_ _GREENTEXT_ _CR_ args);\
        }\
    } while (0)
#else
#define INFO(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define WARNING(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) {\
        uprintf(USE_UART_NR,_BOLDTEXT_ _YELLOWTEXT_ _CR_ args);\
        }\
    } while (0)
#else
#define WARNING(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define ERROR(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) {\
        uprintf(USE_UART_NR,_BOLDTEXT_ _REDTEXT_ _CR_ args);\
        }\
    } while (0)
#else
#define ERROR(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define MSG(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) {\
        uprintf(USE_UART_NR,_BOLDTEXT_ _WHITETEXT_ _CR_ args);\
        }\
    } while (0)
#else
#define MSG(n, args...) do { } while(0)
#endif
 
 
#endif // (__DEBUG_UART__ == 1)
 
 
#if (__DEBUG_UART_DMA__ == 1)
 
#undef __DEBUG_FILE__
#undef __DEBUG_VDSP__
#undef __DEBUG_UART__
#if (AUTOBAUD == 0)
#define DEBUG_OPEN()    UartInitTerminal(USE_UART_NR,USE_UART_BITRATE);\
                        UartDmaInitTx(USE_UART_NR,USE_UART_DMA_NR)
#else
#define DEBUG_OPEN()    UartInitAutobaud(USE_UART_NR);\
                        UartDmaInitTx(USE_UART_NR,USE_UART_DMA_NR)
#endif
#define DEBUG_CLOSE()   UartDmaDisable(USE_UART_NR,USE_UART_DMA_NR);\
                        UartClockDisable(USE_UART_NR)
 
 
#if (__VERBOSITY__ > 0)
#define CONTROL(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) { udprintf(USE_UART_NR,USE_UART_DMA_NR, args); }\
    } while (0)
#else
#define CONTROL(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define DEBUG(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) { udprintf(USE_UART_NR,USE_UART_DMA_NR,_NORMALTEXT_ _CR_ args); }\
    } while (0)
#else
#define DEBUG(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define INFO(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) {\
        udprintf(USE_UART_NR,USE_UART_DMA_NR,_BOLDTEXT_ _GREENTEXT_ _CR_ args);\
        }\
    } while (0)
#else
#define INFO(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define WARNING(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) {\
        udprintf(USE_UART_NR,USE_UART_DMA_NR,_BOLDTEXT_ _YELLOWTEXT_ _CR_ args);\
        }\
    } while (0)#else#define WARNING(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define ERROR(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) {\
        udprintf(USE_UART_NR,USE_UART_DMA_NR,_BOLDTEXT_ _REDTEXT_ _CR_ args);\
        }\
    } while (0)
#else
#define ERROR(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define MSG(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) {\
        udprintf(USE_UART_NR,USE_UART_DMA_NR,_BOLDTEXT_ _WHITETEXT_ _CR_ args);\
        }\
    } while (0)
#else
#define MSG(n, args...) do { } while(0)
#endif
 
 
#endif /* (__DEBUG_UART_DMA__ == 1) */
 
 
#if ( (__DEBUG_VDSP__ == 1) || (__DEBUG_FILE__ == 1) )
 
 
#if (__DEBUG_FILE__ == 1)
#undef __DEBUG_VDSP__
#undef __DEBUG_UART_DMA__
#undef __DEBUG_UART__
#define DEBUG_FILE_NAME     "debug.txt"
#define DEBUG_STREAM        pDebugFile
// либо напрямую используйте fprintf,
#define DEBUG_PRINT         fprintf
#define DEBUG_PRINT_OUTPUT  DEBUG_STREAM
// либо используйте функцию fileprintf, что медленнее
//#define DEBUG_PRINT         fileprintf
//#define DEBUG_PRINT_OUTPUT  DEBUG_FILE_NAME
#define DEBUG_OPEN()        DEBUG_STREAM = fopen(DEBUG_FILE_NAME,"w");\
                            if (DEBUG_STREAM == NULL)\
                            {\
                                fclose(DEBUG_STREAM);\
                                return -1;\
                            }#define DEBUG_CLOSE()       fclose(DEBUG_STREAM)
#endif // (__DEBUG_FILE__)
 
 
#if (__DEBUG_VDSP__ == 1)
    #undef __DEBUG_FILE__
    #undef __DEBUG_UART_DMA__
    #undef __DEBUG_UART__
    #define DEBUG_STREAM        stdout
    #define DEBUG_PRINT         fprintf
    #define DEBUG_PRINT_OUTPUT  DEBUG_STREAM
    #define DEBUG_OPEN()
    #define DEBUG_CLOSE()
#endif // (__DEBUG_VDSP__ == 1)
 
 
#if (__VERBOSITY__ > 0)
#define CONTROL(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) { DEBUG_PRINT(DEBUG_PRINT_OUTPUT, args); }\
    } while (0)
#else
#define CONTROL(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define DEBUG(n, args...)\
    do {\        if (__VERBOSITY__ >= n) { DEBUG_PRINT(DEBUG_PRINT_OUTPUT, args); }\
    } while (0)
#else
#define DEBUG(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define INFO(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) { DEBUG_PRINT(DEBUG_PRINT_OUTPUT," [INFO]"args); }\
    } while (0)
#else
#define INFO(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define WARNING(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) { DEBUG_PRINT(DEBUG_PRINT_OUTPUT,"[WARNING]"args); }\
    } while (0)
#else
#define WARNING(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define ERROR(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) { DEBUG_PRINT(DEBUG_PRINT_OUTPUT,"[ERROR]"args); }\
    } while (0)
#else
#define ERROR(n, args...) do { } while(0)
#endif
 
 
#if (__VERBOSITY__ > 0)
#define MSG(n, args...)\
    do {\
        if (__VERBOSITY__ >= n) { DEBUG_PRINT(DEBUG_PRINT_OUTPUT,"  [MSG]"args); }\
    } while (0)
#else
#define MSG(n, args...) do { } while(0)
#endif
 
 
#endif /* (__DEBUG_VDSP__ == 1) || (__DEBUG_FILE__ == 1) */
 
 
/*******************************************************************************
*
*  Область экспортируемых данных
*
*******************************************************************************/
 
extern char strbuf[STRINGSIZE];
 
#include < stdio.h >
 
#if (__DEBUG_FILE__ == 1)
    extern FILE *DEBUG_STREAM;      // эта переменная должна быть определена глобально,
                                    // и открыта в модуле main.c
#endif
 
#include < device.h >
#include < device_int.h >
 
#if (__UART_IO_DEVICE__ == 1)
    extern DevEntry UartIODevice;   // определено в модуле BfDebugger.c
    extern FILE *pUartIOFile;       // должна быть определена глобально и открыта в main.c
#endif
#define UartIOFileId 3
 
 
/*******************************************************************************
*
*  Область экспортируемых прототипов функций
*
*******************************************************************************/
 
short uprintf(unsigned char UartNum, const char *fmt, ...);
short udprintf(unsigned char UartNum, unsigned char DmaChan, const char *fmt, ...);
short fileprintf(const char *file, const char *fmt, ...);
void WelcomeMessage(void);
void WelcomeMessage2(FILE* fp);
 
#endif // __DEBUG_H__
/******************************** End of File *********************************/

[Практическое использование кода из EE347v03zip.zip]

Что нужно сделать, чтобы добавить в проект отладочный вывод UART:

1. Скачайте пакет EE347v03zip.zip [2] (это примеры кода для EE-347). Оттуда нужно будет брать нужные модули исходного кода и заголовки.

2. Добавьте в проект модули ADSP-BF538-UART.c (если у Вас процессор ADSP-BF538), BfDebugger.c, system.c из этого пакета. Внимание, если у Вас CPP-проект, то переименуйте модули, чтобы у них было расширение *.cpp вместо *.c (иначе получите ошибку линкера li1021). Также в случае CPP-проекта добавьте #define __func__ __FUNCTION__, чтобы определить идентификатор __func__, который автоматически поддерживается только в C99 mode (см. FAQ []).

Примечание: в каталоге VisualDSP 5.0\Blackfin\ldr\init_code\c\src\ может находиться более свежая версия файлов system.c и system.h, чем версия в архиве EE347v03zip.zip.

4. Добавьте в проект заголовочные файлы ADSP-BF538-UART.h, ezkitBF538f_initcode.h (для случая процессора ADSP-BF538), BfDebugger.h, init_platform.h, ivg.h, macros.h, nBlackfin.h, system.h. Все они, как и модули *.c находятся в архиве EE347v03zip.zip.

5. В файле BfDebugger.h замените все esc-коды в виде \e на \x1B, иначе не будут правильно формироваться управляющие последовательности вывода (цвет шрифта и другие функции управления текстом). Пример:

//#define _GREENTEXT_ "\e[32m"
#define _GREENTEXT_ "\x1B[32m"

6. Отредактируйте настройки в заголовочном файле BfDebugger.h, чтобы отладочный вывод удовлетворял Вашим требованиям. Нужно раскомментировать одну из опций __DEBUG_UART__, __DEBUG_UART_DMA__, __DEBUG_FILE__, __DEBUG_VDSP__ (должна быть раскомментирована только одна из них, остальные должны оставаться закомментированными). 

7. Отредактируйте настройки в заголовочном файле ADSP-BF538-UART.h. Нужно выбрать номер порта USE_UART_NR (например, если у Вас для отладки используется UART2, то должно быть задано #define USE_UART_NR 2) и скорость передачи (#define USE_UART_BITRATE 115200).

8. Убедитесь, что функция get_sclk_hz правильно вычисляет системную частоту шины. Если это не так, то скорость выбранного порта UARTx будет настраиваться неправильно. Для того, чтобы исправить ситуацию, можно в функции UartSetBitrate заменить вызов get_sclk_hz() на константу, пример модификации кода UartSetBitrate: 

short UartSetBitrate(unsigned char UartNum, unsigned long UartBitrate)
{
   ...
   //UartDivisor = (get_sclk_hz() / UartBitrate);
   UartDivisor = (32768000 / UartBitrate);
   UartDivisor += 8; // округление вверх перед делением на 16
   UartDivisor >>= 4;
   ...

9. Настройте программу терминала так, чтобы она поддерживала Esc-последовательности, управляющие цветом шрифта. Если Вы используете программу putty, то проверьте настройки сессии в разделе Window -> Colours. Должны стоять галочки "Allow terminal to specify ANSI colours" и "Allow terminal to use xterm 256-colour mode".

putty session settings Window Colours

10. Добавьте перед главным циклом main вызов DEBUG_OPEN(). В программе для вывода сообщений используйте макросы DEBUG, INFO, MSG, ERROR. Для управления цветом текста используйте макросы _MAGENTATEXT_, _YELLOWTEXT_, _REDTEXT_ и т. п. Подробнее про имеющиеся макросы см. файл BfDebugger.h. Пример кода, который выводит отладочные сообщения через UART:

int main()
{
   ...
   ConfigureInputs();
   ConfigureOutputs();
   PowerON();
   DEBUG_OPEN();
   while(1)
   {
      WelcomeMessage();
      DEBUG(1,"This is a debug message"_NL_"");
      INFO(1,"This is a info message"_NL_"");
      MSG(1,"This is a standard message"_NL_"");
      ERROR(1,"This is an error message"_NL_"");
      DEBUG(1,""_MAGENTATEXT_"This "_YELLOWTEXT_"is "_REDTEXT_"a "_BLUETEXT_"multi-"\
              _YELLOWTEXT_"colored "_GREENTEXT_"message"_NL_"");
   }
}

putty colour text example

[Заключение]

В статье описаны методы для создания и вывода отладочной информации без использования медленного окна Output (консоли) среды разработки VisualDSP++. Предоставленные примеры [2] можно использовать вместе с любыми платами разработчика Blackfin EZKIT Lite evaluation board, и их функционал также просто добавить в существующие проекты с аналогичными процессорами.

[Ссылки]

1. Formatted Print to a UART Terminal with Blackfin® Processors site:analog.com.
2. EE347v03zip.zip site:analog.com - примеры кода для организации отладочного вывода через UART Blackfin.
3. VisualDSP++ 5.0 C/C++ Compiler and Library Manual for Blackfin Processors. Rev. 5.2, September 2009 site:analog.com.
4. IAR EWB ARM: форматированный вывод printf библиотеки DLIB.
5. ANSI Escape sequences site:ascii-table.com.
6. VisualDSP++ 5.0 Blackfin examples: Services\File System\VDK\shell_browser\ site:analog.com.
7. VisualDSP++ 5.0 Blackfin examples: LAN\FileServerStdio\ site:analog.com.
8. ADSP-BF538: интерфейс UART.
9. Blackfin пишем драйвер последовательного порта site:kit-e.ru.
10VisualDSP: ввод/вывод с использованием файлов (stdio).

 

Добавить комментарий


Защитный код
Обновить

Top of Page