DSP开发例程(4): logbuf_print_to_uart

DSP开发例程: logbuf_print_to_uart

SYS/BIOS 提供了 xdc.runtime.Log, xdc.runtime.LoggerBufxdc.runtime.LoggerSys 这几个模块用于日志记录. 日志信息在 应用程序调试和状态监控中非常实用. 日志记录函数相较于 System_printf() 占用的时间更短, 且可以区分事件的等级, 如: Info, WarningError 等.

此例程实现将 SYS/BIOS 日志信息通过串口输出, 并在 EVM6678L 开发板上进行了测试. 例程源码可从我的 gitee 仓库上克隆或下载. 点击 DSP 开发教程(0): 汇总查看其他例程说明.

新建工程

此示例工程直接在 sys_print_to_uart 工程基础上修改.

  • 选中 sys_print_to_uart 工程, 右键选择 Copy 或 使用快捷键 Ctrl+C 复制工程.

在这里插入图片描述

  • 在工程浏览视图中, 右键选择 Paste 或使用快捷键 Ctrl+V 粘贴工程.
    在这里插入图片描述
  • 在弹出的 Copy Project 对话框中 修改工程名为: logbuf_print_to_uart, 点击 OK.

在这里插入图片描述

  • 删除 logbuf_print_to_uart 工程中的 Debug目录, 右键选择 Build Project, 编译此工程.

源码编辑

app.cfg

  • 使用 XGCONF 打开 app.cfg 文件.
    在这里插入图片描述
  • 点击 logger0.

在这里插入图片描述- 将 logger0 的句柄设置为 logger0.

在这里插入图片描述- 点击 Timestamp 模块.

在这里插入图片描述

  • 勾选 Add Timestamp to my configuration.

在这里插入图片描述

  • 保存修改.

os.c

编辑 os.c 源文件, 其内容如下:

/*
 * os.c
 *
 *  Created on: 2023-10-26
 *      Author: falwa
 */
#include <xdc/std.h>
#include <xdc/runtime/Log.h>
#include <xdc/runtime/LoggerBuf.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Text.h>
#include <xdc/runtime/Types.h>
#include <xdc/runtime/Timestamp.h>

extern LoggerBuf_Handle logger0;

/*
 *  ======== doPrint ========
 */
Void myLog_doPrint(Log_EventRec *er)
{
    Text_RopeId rope;
    String fmt;
    Bits32 hi, lo;
    Types_FreqHz freq;
    uint32_t msec;

    Timestamp_getFreq(&freq);

    /* print timestamp if there is one; ~0 isn't a valid timestamp value */
    hi = er->tstamp.hi;
    lo = er->tstamp.lo;
    msec = (((uint64_t)hi << 32) | lo) / (freq.lo/1000);

    System_printf("[%5d.%03ds] ", msec/1000, msec%1000);

    /* print event */
    rope = Types_getEventId(er->evt);   /* the event id is the message rope */
    if (rope == 0) {
        /* Log_print() event */
        System_aprintf((String)iargToPtr(er->arg[0]),
            er->arg[1], er->arg[2], er->arg[3], er->arg[4],
            er->arg[5], er->arg[6], 0,          0);
    }
    else {
        /* Log_write() event */
        fmt = Text_ropeText(rope);

        if (Text_isLoaded) {
            System_aprintf(fmt, er->arg[0], er->arg[1], er->arg[2], er->arg[3],
                er->arg[4], er->arg[5], er->arg[6], er->arg[7]);
        }
        else {
            System_aprintf("{evt: fmt=%p, args=[0x%x, 0x%x ...]}",
                fmt, er->arg[0], er->arg[1]);
        }
    }

    System_putch('\n');
}

/*
 *  ======== LoggerBuf_flush ========
 */
Void myLoggerBuf_flush(LoggerBuf_Object *obj)
{
    Int nEntries;
    Log_EventRec evtRec;

    for (;;) {
        nEntries = LoggerBuf_getNextEntry(obj, &evtRec);
        if (nEntries == 0) {
            break;
        }
        else {
            if (nEntries != -1) {
            	myLog_doPrint(&evtRec);
            }
        }
    }
}


/**
 * 添加此函数到 Idle Thread.
 *
 * ```xdc
 * var Idle = xdc.useModule('ti.sysbios.knl.Idle');
 *
 * Idle.idleFxns[0] = "&os_systemFlush";
 * ```
 */
void os_systemFlush()
{
	if (logger0)
		myLoggerBuf_flush(logger0);
	System_flush();
}

/**
 * 将  System_printf() 重定向到  platform_uart_write().
 *
 * 请在 .cfg 中添加:
 * ```
 * SysMin.outputFxn = "&os_systemOutput";
 * ```
 */
Void os_systemOutput(Char *str, UInt len)
{
	UInt i;
	for(i = 0; i < len; i++)
	{
		platform_uart_write(str[i]);
	}
}


其中新增了两个函数 myLog_doPrint()myLoggerBuf_flush() , 这两个函数参考 C:\ti\xdctools_3_25_03_72\packages\xdc\runtime\LoggerBuf.c 中的 Log_doPrint()LoggerBuf_flush() 进行设计. 其中,

  • myLog_doPrint() 用于调用 System_printf() 格式化打印一条日志事件;
  • myLoggerBuf_flush() 负责调用 myLog_doPrint() 格式化 并 flush logBuf 中的所有日志事件.

os_systemFlush() 函数中调用 myLoggerBuf_flush(logger0); 完成日志的 flush.

main.c

编辑 main.c, 其内容如下:

/*
 *  ======== main.c ========
 */
#include <stdio.h>
#include <string.h>

#include <xdc/std.h>

#include <xdc/runtime/Error.h>
#include <xdc/runtime/Log.h>
#include <xdc/runtime/System.h>

#include <ti/sysbios/BIOS.h>

#include <ti/sysbios/knl/Task.h>

#include <ti/platform/platform.h>

/*
 *  ======== taskFxn ========
 */
Void task_ledFlash(UArg a0, UArg a1)
{
	int i = 1;
    Log_info0("enter task_ledFlash().");

    while(1)
    {
    	platform_led(0, PLATFORM_LED_ON, PLATFORM_USER_LED_CLASS);
    	Log_info1("LED 0 ON at %d times.", i);
    	Task_sleep(500);
    	platform_led(0, PLATFORM_LED_OFF, PLATFORM_USER_LED_CLASS);
    	Log_info1("LED 0 OFF at %d times.", i);
    	Task_sleep(500);
    	i++;
    }
}

/**
 * 平台初始化
 */
void EVM_init()
{
	platform_init_flags init_flags;
	platform_init_config init_config;

	// plaform initialize
	memset(&init_flags, 1, sizeof(platform_init_flags));
	init_flags.phy = 0;
	memset(&init_config, 0, sizeof(platform_init_config));
	if (platform_init(&init_flags, &init_config) != Platform_EOK)
	{
		printf("Platform failed to initialize, errno = 0x%x \n", platform_errno);
		while(1);
	}
	platform_uart_init();
}

/*
 *  ======== main ========
 */
Int main()
{ 
    Task_Handle task;
    Error_Block eb;

    Log_info0("enter main().");

    Log_error1("Log_error1(%d)", 1);

    Log_warning2("log_warnning2(%d, %d)", 1, 2);

    Error_init(&eb);
    task = Task_create(task_ledFlash, NULL, &eb);
    if (task == NULL) {
        System_printf("Task_create() failed!\n");
        BIOS_exit(0);
    }

    BIOS_start();    /* does not return */
    return(0);
}

其中 调用了 Log_info#(), Log_error#()Log_warning#() 这几个日志事件记录函数进行测试.

保存上述更改, 并编译工程.

调试

完成编译后, 在 EVM6678L 上调试.

串口通过USB连接计算机. 请确保 COM_SEL1 跳线设置在正确位置. 且在计算机设备管理器中能够找到对应板卡的串口.

在这里插入图片描述

打开串口终端, 连接对应串口, 串口设置如下:

在这里插入图片描述
点击运行按钮, 运行程序. 此时在串口终端中能够看到打印的日志信息. 相较于 System_printf(), 增加了 时间戳, 文件名, 行数等信息.

在这里插入图片描述

说明

这只是 打印日志信息到串口的一种方式. 启用 xdc.runtime.LoggerSys 模块, 也可以实现日志信息的打印, 不过打印的格式不是很好看, 其中的时间戳是16进制显示的. 看图自行体会.

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

falwat

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值