Blackfin: форматированный вывод в окно терминала через UART |
![]() |
Добавил(а) microsin | ||||||||||||||||
В этой статье обсуждается реализация различных функций вывода для семейства Blackfin компании Analog Devices (перевод Engineer-to-Engineer Note EE-347 [1]). Обычно в разных системах программирования это называется перенаправлением вывода printf. Среда разработки VisualDSP++® предоставляет поддержку стандартных C-функций ввода/вывода через такие функции как printf и fprintf. Производительность вывода достаточна для отправки отдельных (не часто повторяющихся) отладочных сообщений в окно Output (консоль терминала) VisualDSP++ IDDE. Однако несколько следующих друг за другом выводов могут повлиять на скорость работы приложения. Рис. 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 Последние 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, /* аргументы */ ...) вывод без окраски, отладочные сообщения Для раскраски выводимых символов используются специальные стандартные управляющие 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__ Следующие определения задают, как будет использоваться UART - ядром или через DMA. Можно выбрать один из 2 вариантов: • __DEBUG_UART_DMA__ После этого любой вывод с помощью функции 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 Все примеры кода ADSP-BF6xx были разработаны и протестированы с использованием: - отладочных плат разработчика Blackfin EZ-KIT II. ОПИСАНИЕ РАБОТЫ Пожалуйста тщательно прочитайте апноут EE-347 вместе с комментариями в исходном коде. Требуемые настройки для переключения между разными поддерживаемыми режимами задаются определениями в файле BfDebugger.h. Вот эти определения (подробнее см. заголовочный файл Common Code\BfDebugger.h):
Больше ничего вообще не должно быть изменено. III. НАСТРОЙКИ АППАРАТУРЫ Номер выбранного порта UART по умолчанию установлен в соответствии с имеющимися коннекторами на отладочной плате. Также поддерживается автодетект скорости. Настройки UART по умолчанию следующие (их можно поменять в специальном файле заголовка ADSP-BF5xx-UART.h): Скорость (bitrate): 115200 Длина слова (количество бит во фрейме RS-232) может быть изменено определением UART_LCR_VAL. Установки переключателей/перемычек должны быть по умолчанию. IV. КАКИЕ ФАЙЛЫ СОДЕРЖАТСЯ В ЭТОМ КАТАЛОГЕ [BfUart] Модули, не привязанные к архитектуре (к типу процессора), находятся в папке 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". 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_""); } } [Заключение] В статье описаны методы для создания и вывода отладочной информации без использования медленного окна Output (консоли) среды разработки VisualDSP++. Предоставленные примеры [2] можно использовать вместе с любыми платами разработчика Blackfin EZKIT Lite evaluation board, и их функционал также просто добавить в существующие проекты с аналогичными процессорами. [Ссылки] 1. Formatted Print to a UART Terminal with Blackfin® Processors site:analog.com. |