This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Get DSP printfs in ARM side

Hi all,

I am new to TI DSP development on TI8148 . Can anybody guide me to get syslink sample's DSP side System_printf() output to ARM side terminal?

It would be great If somebody can give a simple example for the same.

Thanks

Jibin

  • Jibin,

    Syslink samples currently don't support a simple solution for transferring DSP System_printf() output to the ARM.  The plan is actually to replace the System_printf() statements with Log_print(), and then use UIA to enable output of DSP Log data on the ARM.  However, this is not yet available.

    In the meantime, it is possible to view the DSP's System_printf() output on the ARM by using a MessageQ data buffer to copy the System_printf() output to. You would need to do the following:

    1.  In the DSP's configuration file, configure System to use SysMin (not SysStd).  This will cause the output to go to a buffer.  Then configure the SysMin buffer size and output function (which you will add to your DSP app).  The configuration may look something like this:

    var SysMin   = xdc.useModule('xdc.runtime.SysMin');
    SysMin.outputFxn = '&myOutputFxn';
    SysMin.bufSize = 512;
    System.SupportProxy = SysMin;

    2.  Create a MessageQ on the DSP.  Code may look something like this:

        /* Register the NULL heap to heap Id 0. This is ok since we won't be calling MessageQ_alloc(). */
        MessageQ_registerHeap(NULL, 0);

        /* Create the "to server" message queue */
        MessageQ_Params_init(&msgqParams);

        if ((msgq = MessageQ_create(msgqName, &msgqParams)) == NULL) {
            Log_print0(Diags_USER7, "[+7] Error: Failed to create message queue!");
            return (-1);
        }

    3.  The Message object should have a buffer where the System_printf() output will be copied to:

    typedef struct Msg {
        MessageQ_MsgHeader header;
        UInt32             cmd;
        Char               buf[MSGBUFSIZE];
    } Msg;

    4. Create a task to run on the DSP that will loop waiting for a message to dump the System_printf() output:

                mqStatus = MessageQ_get(msgq, (MessageQ_Msg *)&msg,  MessageQ_FOREVER);

                if (mqStatus < 0) {
                    Log_print1(Diags_USER7, "[+7] msgThreadFxn: MessageQ_get() failed (%d)!", (IArg)mqStatus);
                    break;
                }

                if (msg->cmd == DUMPTRACE) {
                    System_printf("msgThreadFxn: Got DUMPTRACE\n");
                    dumpTrace();
                }

                /* Reply back to host with the data */
                sendId =  MessageQ_getReplyQueue((MessageQ_Msg)msg);
                mqStatus = MessageQ_put(sendId, (MessageQ_Msg)msg);

    5.  Write the dumpTrace() function to call System_flush() and reset the message buffer index to 0 when done.  System_flush() will call your output function twice, if the SysMin buffer has wrapped, so we need to set the message buffer index to the next available slot to write to in the message buffer:

    static Void dumpTrace()
    {
        System_flush();
        bufIndex = 0;
    }

    6.  Here is the code for the output funtion (no guarantees that this isn't bug free, since I just whipped it up!)

    Void myOutputFxn(Char *buf, UInt size)
    {
        UInt   n;
        Int    nFree;

        /* Number of free slots in the buffer (leave the last one for a '\0' */
        nFree = MSGBUFSIZE - 1 - bufIndex;

        if (msg != NULL) {
            n = (size > nFree) ? nFree : size;
            memcpy(msg->buf + bufIndex, buf, n);
            bufIndex += n;
            msg->buf[bufIndex] = 0;
        }
    }

    I made bufindex and msg static variables in the file so that they would be accessible by the output function.

    7. For the ARM side app, create a heap in shared memory where messages will be allocated from:

        HeapBufMP_Params_init(&heapParams);
        heapParams.align = 128;
        heapParams.numBlocks = 16;
        heapParams.blockSize = 0x400;
        heapParams.sharedAddr = NULL;
        heapParams.regionId = 0;
        heapParams.name = "MESSAGE_APP_HEAP";
        heapBuf = HeapBufMP_create(&heapParams);

        if (heapBuf == NULL) {
            fprintf(stderr, "Error: can't create heap for messages!\n");
            goto done;
        }

        mqregStatus = MessageQ_registerHeap((Ptr)heapBuf, heapId);

    8.  For you ARM side app, open the MessageQ for sending to the DSP and create a reply MessageQ object for the reply from the DSP.  Also allocate the message object:

        do {
            mqStatus = MessageQ_open(toServerMsgqName, &toMsgqId);
            ++retries;
        } while ((retries <= maxrtries) && (mqStatus < 0));

        /* Create the "from server" message queue */
        MessageQ_Params_init(&msgqParams);

        if ((fromQ = MessageQ_create(fromServerMsgqName, &msgqParams)) == NULL) {
            fprintf(stderr, "Error: can't create to server message queue!\n");
        }

        /* Allocate a message */
        msg = (Msg *)MessageQ_alloc(HEAPID, sizeof(Msg));

    9.  Now you should be able to send a message from the ARM to the DSP telling it to dump the trace:

            msg->cmd = DUMPTRACE;

            /* Put the queue for the server to reply to in the message */
            MessageQ_setReplyQueue(fromQ, (MessageQ_Msg)msg);

            mqStatus = MessageQ_put(toMsgqId, (MessageQ_Msg)msg);

            /* Wait for server to send ack */
            mqStatus = MessageQ_get(fromQ, (MessageQ_Msg *)&msg, MessageQ_FOREVER);

            dumpTrace(msg);

     

    I tried this out as part of one of my test examples.  Since this particular test has a lot of other stuff unrelated to dumping trace, I didn't just post the sources.  However, it wouldn't be too difficult to put together a simple example that just illustrates the System_printf() output through MessageQ, so I can post this later when I get it working.

    Best regards,

        Janet

     

  • That sounds like if this article about CE_DEBUG is currently wrong?

    How about EZSDK 5.03.01.15, is it there as well such a bigger hack to get some trace lines from a DSP side running codec, driven by CodecEngine/CodecServer?

    Or should that all run as used from older EZSDK versions, and maybe I've overlooked somewhat?

    Thanks,
    Joern.

  • Joern,

    If you are using Codec Engine, then you can get DSP trace using the CE_DEBUG feature of Codec Engine, as described in this article:

    http://processors.wiki.ti.com/index.php/CE_DEBUG

    If you are only using SysLink, then you would need such a method as described in the earlier post on this thread, to get trace from the DSP.

    Best regards,

        Janet

  • Janet,

    that sounds good - but unfortunately it doesn't work for me.

    Currently I work with EZSDK 5.03, and I've the need to get some trace lines from a codec, driven by Codec Engine. As far as I remember, with earlier EZSDK versions (and the corresponding examples) I got that without further circumstances by use of the TRACE_*print functions, which had been activated for the debug targets.

    Now within the CE's universal_copy sample, there in UniversalCopy.xdc I found a setting enableTrace. But setting this to true I get a linker error for the all_codecs server. And with enableTrace=false the TRACE_*print calls are disabled (and so can't be activated by CE_DEBUG setting).

    Best regards,
    Joern.

    P.S.

    Got traces running again by use of  Log_print* instead of these peculiar TRACE_*print functions...

    It was actually nice if sometime all CE samples would be compilable and running without any circumstances, to faster get them useable for comparisons with own code...

    Besides, I wonder of what state the next EZSDK will be? The first I got was delivered as Release, a newer one came with state Beta, and now, the 5.03 is announced as being Alpha...

  • Joern,

    Ok, I see now.  You can add Log_print() statements in your codec (not sure it will pass Qualiti with that) and running with CE_DEBUG=2 will bring that trace to the ARM.

    You may also enable universal_copy trace by adding these two lines to the all_codecs.cfg file, which I believe is what you tried:

    var uc = xdc.useModule('ti.xdais.dm.examples.universal_copy.UniversalCopy');
    uc.enableTrace = true;

    Now if you try to build you will get a link error, but you can resolve this be adding the following code to your server:


    #include <xdc/std.h>

    #include <ti/xdais/trace.h>
    #include <xdc/runtime/System.h>


    static XDAS_Int32 myAssert(IALG_Handle alg,
            XDAS_Int32 classId, String format, String arg1, XDAS_Int32 arg2);

    static XDAS_Int32 myPrint(IALG_Handle alg, XDAS_Int32 classId,
            String format, ...);

    /* ti/xdais/trace.h exposes the symbol XDAIS_TRACE_assert that needs to be
       defined by a suitable implementation of the 'assert' function */
    XDAIS_TRACE_AssertFxn XDAIS_TRACE_assert = myAssert;

    /* ti/xdais/trace.h exposes the symbol XDAIS_TRACE_print that needs to be
       defined by a suitable implementation of the 'print' function */
    XDAIS_TRACE_PrintFxn XDAIS_TRACE_print = myPrint;

    static XDAS_Int32 myAssert(IALG_Handle alg,
            XDAS_Int32 classId, String format, String arg1, XDAS_Int32 arg2)
    {
        return (0);
    }

    static XDAS_Int32 myPrint(IALG_Handle alg, XDAS_Int32 classId,
            String format, ...)
    {
        va_list va;

        va_start(va, format);

        System_vprintf(format, va);

        va_end(va);
        return (0);
    }

    Then you don't have to modify the codec code.  It looks like we should add something like this to DAIS, so you can just configure it in.  Currently, there is only a "cio" trace implementation in DAIS, which uses stdio, so that will not work for getting DSP trace to the Arm.

    Best regards,

        Janet

  • Hi Janet,

    thank you, that was an actually concrete and helpful hint - although I was near to just change all needed outputs to Log_print() I wanted to get deeper into that and tried your second suggestion concerning defining own XDAIS_TRACE_* functions.

    I just copied your code into tracing.c.

    But adding it to the all_codecs server (within package.bld) I had no success, the linker error remained. Also I didn't get it to set enableTrace to true within all_codecs configuration files. Maybe this is because there the codec is indirectly included via a codecs package (f.e. from ti/sdo/ce/examples/codecs/universal_copy), which itself includes the XDAIS codec (f.e. ti/xdais/.../universal_copy) by a 'requires ..." line. However, not sure about possible faults by me, and yet not happy about all these RTSC configuration files far from a clean makefile project, maybe more flexibe, but for sure less clear for me.

    So I switched to adding the tracing.c module directly to my XDAIS codec, copied it to the same directory (for the TI-CE samples that would be ti/xdais/.../universal_copy), added the module within the package.bld there (something like: var SRCS = ["universal_copy", "tracing"];), and last not least set enableTrace=true directly where it also was suggested by the sample code in ti/xdais/.../universal_copy/UNIVERSAL_COPY.xdc.

    Now it works, and the first outputs from the universal_copy sample are received already at CE_DEBUG=0 level (where I yet don't see a clear connection between these CE_DEBUG levels and the TRACE classes).

    Best regards, and thanks again,
    Joern.

    P.S. As this thread isn't initiated by me unfortunately I have no chance to mark your answer as verified to be helpful - but actually it was. And it was - by far - not the first case that you spent the right hint to get some more understanding of the Codec Engine stuff, thank you very much!

  • Hi Joern,

    I'm not sure why you would have gotten a link error after adding your tracing.c file to the all_codecs package.bld.  I am attaching my package.bld, all_syslink.cfg and trace.c files so you can compare with yours:

    With these files, I was able to get trace output from the universal_copy codec when running the universal_copy remote app with CE_DEBUG=2.

    The CE_DEBUG level (eg, 1, 2, or 3) only affects the levels of trace that are enabled from Codec Engine and Framework Components modules, but setting CE_DEBUG to 0, 1, 2, or 3 will cause the DSP trace to be sent to the Arm during certain Codec Engine calls (eg, when a codec is created or deleted).  In my simple print function in trace.c, I ignore the trace level (classId parameter), so all trace from the universal_copy codec is logged regardless of what CE_DEBUG is set to.  This is why you are seeing trace from universal_copy when you set CE_DEBUG.

    Best regards,

        Janet

  • I thought I had attached those files, but it looks like it didn't work.  Here is my second attempt.

    4188.all_syslink.cfg.txt

    2022.package.bld.txt

    2821.trace.c.txt

  • Thanks a lot, Jane, these sample files enabled me to very fast find out what my failure has been.

    My linker problem adding the tracing module to all_codecs server was caused by a wrong placing within package.bld (added it 3 lines deeper than you, beneath "setid.c", but obviously that line is active for hardware I am not using.

    Additionally I produced problems because of a misunderstanding: While setting the codec's enableTrace to true by something like

    var uc = xdc.useModule('ti.xdais.dm.examples.universal_copy.UniversalCopy');
    uc.enableTrace = true;

    and looking at that I persuaded myself to try to add this codec directly to the codec server by that lines (and spare the ce codec package), what of course is wrong because it is an xDAIS algorithm and has to be wrapped by an ICodec interface before integrating it into the codec server.

    On the other side, alternately, I tried to access enableTrace somehow directly from the ICodec capsule...

    So far about my wrong tracks, maybe it prevents others from the same...

    And, of course, it is much more flexible (and can prevent linker conflicts) to add this tracing code to the codec server (and not to each single codec itself)...

    What actually remains is not too important for me at the moment, but I digged around and have nothing found, maybe someone has a hint for me:

    How to get the currently set CE_DEBUG level (or any TRACE level information depending on it) for comparision with the classId, to bei able to control the amount tracing messages depent to current needs?

    I digged around and was somewhat surprised to find near to nothing, f.e. at TI E2E a search for "XDAIS_TRACE_PrintFxn" delivered nothing but this thread... Is there any Function or global variable accessible which deliveres the current trace level at DSP side?

    Best regards,
    Joern.

  • Hi Joern,

    It may be difficult to tie CE_DEBUG levels to your trace function, however, there is another environment variable that could be used, called CE_DSP0TRACE.  This will allow you to set the xdc.runtime.Diags mask of any of the xdc modules in your server on the command line.  For example, you can run:

    CE_DEBUG=2 CE_DSP0TRACE="xdc.runtime.Main=EX1234" ./app_remote.xv5T

    and this enables logging of the module xdc.runtime.Main (Note that logging for xdc.runtime.Main is already enabled in the configuration file, server_log.cfg, which is included by all_syslink.cfg, so you would already be seeing trace from xdc.runtime.Main when you run with CE_DEBUG=1,2, or 3).

    Now, you can tie your TRACE levels to those of xdc.runtime.Main using the function Diags_query() to see which bits in the diagnostic mask of xdc.runtime.Main are set.  Here is an example:

        switch (classId) {
            case TRACE_ENTER:
                if (Diags_query(Diags_ENTRY | Diags_EXIT)) {
                    System_vprintf(format, va);
                }

                break;

            case TRACE_1CLASS:
                if (Diags_query(Diags_USER1)) {
                    System_vprintf(format, va);
                }
                break;

            case TRACE_2CLASS:
            case TRACE_3CLASS:
            case TRACE_4CLASS:
            default:
                if (Diags_query(Diags_USER2 | Diags_USER3 | Diags_USER4)) {
                    System_vprintf(format, va);
                }
                break;
        }

    When I ran the universal_copy with:

    CE_DSP0TRACE="xdc.runtime.Main=EX1234" CE_DEBUG=2 ./app_remote.xv5T -s xe674

    I got all the trace from the universal_copy codec.  I then ran:

    CE_DSP0TRACE="xdc.runtime.Main=1234" CE_DEBUG=2 ./app_remote.xv5T -s xe674

    and no longer got the TRACE_ENTER trace.

    I'm attaching my trace.c file that you can try out.


    8233.trace.c.txt

    As far as I know, the XDAIS_TRACE is not documented other than in the header trace.h.

    Best regards,

        Janet

  • Janet, thank you VERY much, it worked at once.

    And all your concrete hints within this thread give, in my opinion, the best entry into that problem that currently is available.

    Some additional digging within the sources brought me a vague insight how the different trace level systems are connected, so f.e. from <ezsdk>/dsp-devkit/packages/ti/sdo/ce/utils/rtcfg/rtcfg.c how the CE_DEBUG levels influence the DIAGS mask, and how these strings you spent at CE_DSP0TRACE actually influence the DIAGS mask (<ezsdk>/component-sources/xdctools_3_22_04_46/packages/xdc/runtime/Diags.c). It feels somewhat like a jungle...

    I think, now I'll let linger that in my mind for a while, and when I find a little time for that I'll add all these information into the TI wiki, where I missed them so much before asking first within this thread...

    Thanks again,
    best regards,
    Joern.

  • Hi Joern,

    I'm glad to hear that this worked for you.  One thing I would like to correct in the trace.c file I posted:  The TRACE_nCLASS defines in the ti/xdais/trace.h file are actually bit masks so technically, you could have trace statements in your algorithm, such as:

        TRACE_1print((IALG_Handle)NULL, TRACE_4CLASS | TRACE_ENTER,
                "UNIVERSALCOPY_TI_alloc> memTab[0] size=0x%x, alignment=0, "
                "space=IALG_EXTERNAL, attrs=IALG_PERSIST\n", memTab[0].size);

    So, instead of the 'switch()' in trace.c, you could have for example:

        if (classId & TRACE_ENTER) {
            if (Diags_query(Diags_ENTRY | Diags_EXIT)) {
                System_vprintf(format, va);
            }
        }
        else if (classId & TRACE_1CLASS) {
            if (Diags_query(Diags_USER1)) {
                System_vprintf(format, va);
            }
        }
        else {
            if (Diags_query(Diags_USER2 | Diags_USER3 | Diags_USER4 |
                            Diags_USER5 | Diags_USER6 | Diags_USER7)) {
                System_vprintf(format, va);
            }
        }

    I lumped everything other than TRACE_ENTER and TRACE_1CLASS together just for illustration, but you can do whatever you want since the trace.c file is part of your app code.

    Thanks for digging into this and bringing these issues to our attention.

    Best regards,

        Janet