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.

RTOS/66AK2G02: How to create my own UIA consumer?

Part Number: 66AK2G02
Other Parts Discussed in Thread: DA8XX

Tool/software: TI-RTOS

We wrote our own code to retrieve the LOG_printf() buffers without using CCS in our current L137/DA8xx product.  I want to do the same on the K2G.  

I see that the UIA is now more fully deployed and the successors to LOG_printf() have developed in some good ways.   It looks to me like the UIA supports the concept of a consumer, and the right way to implement this would be to write my own consumer.

I find the files traceframework.c/h in the keystone-rtos-traceframework git repository.  But I don't see this distributed in the processor SDK or UIA.  Can you recommend how I should structure such a project?  Are functions like these distributed in a release package that I'm missing?  Or should I just follow them from the git repository?  

  • By consumer, do you mean you want to write host code that interprets the Log records? Basically a replacement to System Analyzer in CCS?
  • Yes. On my existing L137 system the ARM can request the trace buffer from the DSP and interpret it for display. It looks up the strings in the out file. We consider this a necessary function. In the new systems I see that the UIA has this function. I expect to fetch the raw buffer from the DSP and share it with a tool of my own construction that can look up the strings and print them. I am also interested to extend this function to the task switch tracing. I'd most like to use a proper UIA interface to do this.
  • You can do this also with UIA. Are you just pulling the log buffers from the target? If so, you need to use LoggerStopmode. There are two key data structures you need to learn.

    ti.uia.runtime.EventHdr: This describes the contents of each log record.
    ti.uia.runtime.UIAPacket: This describes front of the buffer. Note: with UIA there are commands from the host to the target also. This is not applicable for LoggerStopmode though....just a heads-up to avoid confusion.

    The cdoc (or the xdc file) has a description of the different fields in the buffer
  • The pointer to the cdoc directory in the UIA package looks very helpful. Thanks.
    You haven't said that I should not try to do this. But you haven't answered my question about the consumer API.
    I can see consumer.h in the git repo, but not in the UIA package. Can you help me understand the disconnect? Is there any good example to start from?
  • I took a quick look at the git repo. This was done by the device team (I'm with the TI-RTOS team). I'll move this thread to the device forum as they may have something for UIA that I don't know about (like they did with LOG).

    Todd
  • I'll explain some more as you look for the folks with the expertise.

    Let's say the DSP code is constructed to have a 1k entry circular buffer used for LOG_printf.  This is configured in the .cfg file.  This implies that there exists in memory somewhere a block of 1k entries.  We have all of this working on the L137/DA8xx.  We are able to find the pointer to this block of data.  We know its structure.  At any point we can grab the contents and decode it.  Each entry has an offset into the out file for the control string and the params.

    Now I want to do the same thing on the K2G.  Todd recommended the methods in the UIA cdoc.  These are called in my code via macros constructed by the .cfg file.  I see the "metaonly struct LoggerStopMode.RecordView" which seems to describe what is written in the buffer.  I have to guess which entry translates to an offset in the out file for the string, but I can do that.  In general, it looks like I need to reverese engineer it as I don't see an API to fetch the buffer.  But there is some guidance.  

    By contrast, the "keystone-rtos-traceframework" describes this producer/consumer relationship.  I want to be a consumer.  But the buffer structure is still defined by UIA.

    So I can see three possible answers to my question.

    1. TI doesn't support that, you're on your own.
    2. Use the UIA API as described.   A good example is ???
    3. Use the producer/consumer model found in the keystone-rtos-traceframework.  A good example is ???

    I'm happy with (1) if that's the best we can do.  I just want to be sure I'm not leaving a better option "on the table".

  • #1. You can use the cdoc for UIAPacket and EventHdr to see the layout of the headers to help write the decoding code. For example each record starts with this

    The start of the buffer is a UIAPacket_Hdr.  Note: this is all assuming you are using LoggerStopMode in UIA.

    Todd

  • I interpret this answer to say I should do it as I did in the past. No fancy new API's. Reverse engineer with the debugger. I investigated with the debugger on the ARM. I can map some of it to the UIAPacket type as described. Thank you, and we can close this.

    For others, this is what I see using this test code:
    Log_info0("\n Program Start.");
    Log_info1("Log_info1 %d.", 47);
    Log_info2("Log_info2 %d %d.", 100, 102);
    Log_info3("Log_info3 %d %d %d.", 1, 2, 3);
    Log_info4("Log_info4 %d %d %d %d.", 4, 3, 2, 1);
    Log_info5("Log_info5 %d %d %d %d %d.", 10, 9, 8, 7, 6);

    I can see that the log buffer is found in
    ti_uia_loggers_LoggerStopMode_Instance_State_1_packetArray__A

    There are 4 32 bit words at the start of the buffer. Then each entry is either 8 (write4) or 12 (write8) 12 32 bit words.
    The word 8 packets are used for Log_info0() and Log_info1(). The 12 word packets are used for the bigger log functions.

    The system writes 9 or 13 words each time, then backs up and overwrites the last word.
    You can see this in the comments in ti_uia_loggers_LoggerStopMode_write8__E():
    > /*
    > * Store an empty event header containing the just-written event length
    > * in the previous event lenght field in order to allow the host to read
    > * events safely from partially written packets
    > */

    Word [0] is the header.
    The empty header begins with 0x4000xxxx.
    8 word blocks with no args begin with 0x502000xx.
    8 word blocks with one arg begin with 0x502004xx.
    12 word blocks begin with 0x503006xx.
    The lower bytes of the header clearly increment.
    Word [1] is a timestamp? It's incremented by a few hundred hex each time.
    Word [2] is the high word of a timestamp?
    Word [3] is the same in each case. 0x15d28009.
    Word [4] is the address of the start of the string table.
    Word [5] is a counter incremented by one each time, but not started at zero, (0x91, 92, 93, 94, 95)
    Word [6] is the address of the string in memory.
    Words [7], [8], [9], [10] and [11] are the parameters (up to 5 of them in a 12 word packet).