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.

SYS/BIOS IOM Adapter and Streams

Hello again,

I am using XDC v3.23.2.47 with SYS/BIOS 6.33.5.46. IPC is version 1.24.3.32 and I also have PSP 3.0.1.00. All using CCSv5.1.

I am trying to get the IPC IOMAdapter with streams to work with an old iom driver written for DSP/BIOS 5. I am currently having 2 problems.

First, I notice when my program comes out of c_int00() that SYS/BIOS is calling my IOM Adapter create() function before bind(). This is a problem because bind is suppose to setup my device (*devp) with the parameter devParams which is later used in create(). Is this intended behavior, or am I doing something wrong? I am currently able to work around this by finding out where my devParams are in memory and changing the *devp when create() is called. Here is the driver and streams setup:

var IomParams = new IomAdapter.Params();
IomParams.instance.name = "myIOM";
IomParams.iomFxns = "&IomFunctions";
IomParams.initFxn = "&IomInit";
IomParams.deviceId = 0;
IomParams.deviceParams = null;
Program.global.myIOM = IomAdapter.create(IomParams);
DriverTable.addMeta("/myIOM", Program.global.myIOM);

var stream0Params = new Stream.Params();
stream0Params.instance.name = "stream0";
Program.global.stream0 = Stream.create("/myIOM", Stream.OUTPUT, stream0Params);

var stream1Params = new Stream.Params();
stream1Params.instance.name = "stream1";
Program.global.stream1 = Stream.create("/myIOM", Stream.INPUT, stream1Params);

Simple producer/consumer tasks using the two streams as inputs:

var task0Params = new Task.Params();
task0Params.instance.name = "task0";
task0Params.arg0 = Program.global.stream1;
task0Params.priority = 2;
Program.global.task0 = Task.create("&task0Fxn", task0Params);

var task1Params = new Task.Params();
task1Params.instance.name = "task1";
task1Params.arg0 = Program.global.stream0;
task1Params.priority = 3;
Program.global.task1 = Task.create("&task1Fxn", task1Params);

The second issue I am seeing is that both my streams (one input and one output) are giving IOM_READ commands in their IOM_Packet. When I do a Stream_issue() on both streams I go to my IOM_Submit() function. One of the parameters is a pointer to IOM_Packet. I believe my OUTPUT stream is suppose to give a IOM_WRITE command instead of an IOM_READ command (this is how the driver was written for DSP/BIOS 5). If I manually change this value during debug to IOM_WRITE my program works as I expect. What am I doing wrong to have both streams appear as reading?

Here's my tasks:

Void task0Fxn (Stream_Handle inStream)
{
	unsigned char bufferIN[1];
	xdc_Ptr myBuf1;
	unsigned char i;
	unsigned long counter=0;
	while(1)
	{
		for (i = 0; i < 1; i++)
		{
			bufferIN[i] = counter++;
		}

		Stream_issue(inStream, bufferIN, sizeof(bufferIN), NULL, NULL);    /* IOM_READ */

		Stream_reclaim(inStream, &myBuf1, BIOS_WAIT_FOREVER, NULL, NULL);
	}
}


Void task1Fxn (Stream_Handle outStream)
{
	unsigned char bufferOUT[1];
	xdc_Ptr myBuf2;
	while(1)
	{
		Stream_issue(outStream, bufferOUT, sizeof(bufferOUT), NULL, NULL); /* IOM_READ */
		Stream_reclaim(outStream, &myBuf2, BIOS_WAIT_FOREVER, NULL, NULL);
	}
}

Thanks for any help!

  • Still have not found an explanation or documentation explaining these issues. Given how streams work in DSP/BIOS I do not believe this is desired behavior.

  • Marshall,

    Your config script and C code look fine.  It seems you are doing all the right things.  I am going to have to discuss this internally and get back to you…

    Scott

  • Thanks for the update Scott. Please let me know if I can help by providing any more information or articulating anything I have made unclear.

  • Marshall,

    For the first issue about the startup sequence, I think this is because the streams are being statically created.  There is a note about how this changes the startup sequence in the IPC and I/O user’s guide (http://www.ti.com/lit/ug/sprugo6d/sprugo6d.pdf)

    For the second issue, can you check that the stream handles being passed into the task functions are correct?  I’m wondering if somehow the same handle is being used by both functions (so the IOM packets are always carrying READ).

    Can you pull up the ROV tool and look at what is shown for the Streams?  Does this look correct?

    Also, I’m wondering why you have both a buffer and a buffer pointer in each task, and are passing one to issue and the other to reclaim.  Normally you’d just have a single buffer in each, and pass it to both the issue and reclaim calls.  As is it shouldn’t be causing a problem, but the usage is not typical.

    Scott

     

  • Scott,

    First issue: I missed that note in the IPC User's Guide. I agree with you that this is likely what has happened and that my driver code must be written in a way to account for this. It has made for some ugly code, but I think it is working for now. Looking forward, I don't know if this will be an issue because I think we will be forced to declare streams at runtime because tasks only take 2 parameters (we have been trying to avoid dynamic creation). Thanks for resolving this issue!

    Second issue: I've looked at the ROV for my streams and everything appears normal. The two streams do not share the same address and the modes display as expected. The streams are also passed into the functions correctly (verified by stepping through code). The code has changed a bit from my original post, but the userSuppliedSync and issue columns below agree with how I've configured them. Both streams are still submitting IOM_READ commands.

    As far as using 2 different buffers for reclaim/issue, I was at one point having an issue when they both were the same buffer. I would get an immediate system abort() on reclaim or issue (can't remember which). I changed them to try to target down specific problems, but I will go back and look more closely at this issue now. I seem to get the abort() problem quite frequently and each time it has ended up being a configuration setting is incorrect.

  • Marshall,

    Thanks for checking the stream handles and ROV contents.

    Is it possible to step the code into the Stream_issue() for the write, and see where the wrong IOM_READ is being picked up?  

    Also, as suggested on the other thread (http://e2e.ti.com/support/embedded/bios/f/355/t/192759.aspx), is it an option for you to use the simpler GIO interfaces instead?

    Scott

  • Scott Gary said:

    Marshall,

    Thanks for checking the stream handles and ROV contents.

    Is it possible to step the code into the Stream_issue() for the write, and see where the wrong IOM_READ is being picked up?  

    Also, as suggested on the other thread (http://e2e.ti.com/support/embedded/bios/f/355/t/192759.aspx), is it an option for you to use the simpler GIO interfaces instead?

    Scott

    I feel kind of stupid, but I can't figure out how to enable debugging symbols for SYS/BIOS modules so I haven't been able to step through Stream to find the issue. I've made sure I'm using "Full symbolic debug" in project properties compiler basic options. I've also set the RTSC build-profile as debug and I have no optimization on. I've played with a bunch of settings. The most promising looks like under project properties->Debug there is a field "OS Aware Debug Options", but none of them seem to allow me to set a breakpoint in Stream.c. Is there something I'm missing?

    I'll look into using GIO instead of Stream. Upon quick initial inspection in the user guides the sections look almost copy and pasted. GIO is only dynamically created but other than that they look identical.

  • Marshall,

    You shouldn’t need to do anything additional to get debug symbols for Stream.  Tomorrow morning I will have access to a board that I can try this on myself, and I’ll reply back then…

    The main reason for the GIO suggestion regards its simpler implementation.

    Scott

  • Scott,

    I read up on the GIO interface and tried to convert my code from Stream to GIO. This is in the code below. Honestly, after reading the documentation, I wouldn't be able to explain to someone the difference between GIO and Stream other than the fact that GIO seems more restrictive and it is a part of the SYS/BIOS package (thus not needing IPC). It's restrictive in that GIO must be defined dynamically (which I think, by definition, must mean tasks are also dynamically created) and also the blocking timeout must be determined upon GIO creation (rather than during buffer issue like with Stream). I don't think either of these restrictions are a big deal for us, but they are the only differences I can point out between GIO and Stream.

    Taking all tasks out and just using GIO issue/reclaim in main() showed promise as in my driver I was getting both IOM_READ and IOM_WRITE. However, when I add a task my Task_Handle is always NULL. I found it interesting that if I comment out all my GIO function calls in the task I am trying to create, the task create's fine and executes normally! I put the GIO issue/reclaim/prime function calls back in the task and the task fails to create again. For fun, I also tried putting GIO functions in my custom user idle function (outside the task) and the task creation still failed. Any idea why adding GIO functions to a task would cause the task to fail to create?

    So here's my code with Stream_issue's replaced with GIO_issue, etc. I do use a custom user idle function to simulate my writer class waking up at a later time to some sort of input.

    #include xdc/std.h>
    #include xdc/runtime/System.h>
    #include xdc/runtime/Error.h>
    #include ti/sysbios/BIOS.h>
    #include ti/sysbios/knl/Queue.h>
    #include ti/sysbios/knl/Task.h>
    #include ti/sysbios/io/IOM.h>
    #include ti/sysbios/knl/Event.h>
    #include ti/sysbios/knl/Clock.h>
    #include ti/sdo/io/Stream.h>
    #include ti/sysbios/io/GIO.h>
    #include xdc/cfg/global.h>
    unsigned char WaitForInput;
    static Void task0Fxn(GIO_Handle outStream);
    static Void task1Fxn(GIO_Handle inStream);
    GIO_Handle handleIN, handleOUT;
    Task_Handle task0, task1;
    /*
    * ======== main ========
    */
    Int main(Int argc, Char* argv[])
    {
    GIO_Params gioParams;
    Task_Params task0Params, task1Params;
    Error_Block eb;
    GIO_Params_init(&gioParams);
    // gioParams.__size = 1;
    gioParams.timeout = BIOS_WAIT_FOREVER;
    gioParams.numPackets = 2;
    gioParams.model = GIO_Model_ISSUERECLAIM;//GIO_Model_STANDARD;
     handleIN = GIO_create("/BSP_DivertToEI", GIO_INPUT, &gioParams, NULL);
    handleOUT = GIO_create("/BSP_DivertToEI", GIO_OUTPUT, &gioParams, NULL);

    Task_Params_init(&task0Params);
    task0Params.stackSize = 512;
    task0Params.arg0 = (xdc_UArg)handleOUT;//&handleOUT;
    task0Params.priority = 2;
    task0 = Task_create((Task_FuncPtr)task0Fxn, &task0Params, &eb);
    //
    // Task_Params_init(&task1Params);
    // task1Params.stackSize = 2048;
    // task1Params.arg0 = (xdc_UArg)&handleIN;
    // task1Params.priority = 3;
    // task1 = Task_create((Task_FuncPtr)task1Fxn, &task1Params, &eb);
    if (task0 == NULL)// || task1 == NULL)
    {
    System_abort("");
    }
    BIOS_start();
    return(0);
    }
    /*
    * ======== tsk0Fxn ========
    * Task that owns input channel
    */
    Void task0Fxn(GIO_Handle outStream)
    {
    unsigned char bufferOUT[1];
    unsigned char i;
    unsigned long counter=1;
    xdc_SizeT Size;
    unsigned char Run = 1;
    /* Load static buffers - OUTPUT */
    // GIO_prime(outStream, bufferOUT, 1, NULL);
    GIO_issue(outStream, bufferOUT, 0, NULL);
    GIO_issue(outStream, bufferOUT, 0, NULL);
    while(Run == 1)
    {
    /* Simulate waiting for input to wake task up */
    WaitForInput = 1;
    Clock_tickStart();
    while (WaitForInput == 1)
    {
    Task_sleep(10);
    }
    // GIO_reclaim(outStream, (xdc_Ptr)bufferOUT, &Size, NULL);
    for (i = 0; i < 1; i++)
    {
    bufferOUT[i] = counter++;
    }
    // GIO_issue(outStream, bufferOUT, sizeof(bufferOUT), NULL);
    }
    }
    Void userIdle1(void)
    {
    unsigned char deleteResources = 0;
    WaitForInput = 0;
    unsigned char bufferOUT[1];
    unsigned char bufferIN[1];
    xdc_SizeT Size;
    if (deleteResources == 1)
    {
    // GIO_issue(handleIN, bufferIN, sizeof(bufferIN), NULL);
    // GIO_issue(handleOUT, bufferOUT, 0, NULL);
    // GIO_reclaim(handleOUT, (xdc_Ptr)bufferOUT, &Size, NULL);
    // GIO_reclaim(handleIN, (xdc_Ptr)bufferIN, &Size, NULL);
    Task_delete(&task0);
    GIO_delete(&handleIN);
    GIO_delete(&handleOUT);
    }
    }
    Void task1Fxn(GIO_Handle inStream)
    {
    unsigned char bufferIN[1];
    // xdc_Ptr myBuf2;
    xdc_SizeT Size;
    /* Load static buffers - INPUT */
    GIO_issue(inStream, bufferIN, sizeof(bufferIN), NULL);
    GIO_issue(inStream, bufferIN, sizeof(bufferIN), NULL);
    while(1)
    {
    GIO_reclaim(inStream, (xdc_Ptr)bufferIN, &Size, NULL);
    //process incoming data
    GIO_issue(inStream, bufferIN, sizeof(bufferIN), NULL);
    }
    }
  • Marshall,

    OK thanks for switching to GIO, and for the update.

    It doesn’t make any sense to me that the Task_create() calls will fail just because the task’s function has GIO_issue()/GIO_reclaim() calls in it.  The only things I can think of are if the memory allocations for the task’s stack or hooks are failing, or the creation hooks (if used) return errors.  But those don’t really fit with what you describe. 

    Is it possible that your Task.defaultStackHeap is running out of space?

    I will send some pings internally to see if any others have ideas…

    Scott

  • Scott Gary said:

    Marshall,

    OK thanks for switching to GIO, and for the update.

    It doesn’t make any sense to me that the Task_create() calls will fail just because the task’s function has GIO_issue()/GIO_reclaim() calls in it.  The only things I can think of are if the memory allocations for the task’s stack or hooks are failing, or the creation hooks (if used) return errors.  But those don’t really fit with what you describe. 

    Is it possible that your Task.defaultStackHeap is running out of space?

    I will send some pings internally to see if any others have ideas…

    Scott

    Scott,

    No task hooks are used. I thought it might be stack sizes or some other memory allocation as well. Something related to running the program and making a change and rerunning without ever calling a delete(). For this reason I added the option to delete resources in my idle function (although I don't know if this is proper usage, but I don't know how to return from BIOS_start() either to do it in main).

    I doubled the default heapMem from 8192 to 16384 and had no luck. Looking at ROV it doesn't look remotely close to filling (something like 0x3e30 free of 0x4000). I am still not able to debug step into these module functions to see what might be going on.

    But now for some good news, I moved the task back to being created statically in the configuration file. My GIO_Handle is just a global variable in my main file and no arguments passed into the task. The task creates and runs fine with GIO functions. I'm not sure how this might help us figure out why the dynamic task creation fails.

    Marshall

  • Scott,

    I think I've found my error in dynamically creating the tasks. I had not initialized my Error_Block. Setting this parameter to NULL, initializing the Error_Block pointer, eb, to NULL, or using the Error_init() function all seem to have task creation going smoothly. I'm not sure on the inner working on why/how that relates to the GIO calls, but nonetheless, I can keep moving forward!

    So I guess I'll move along using GIO - is there a reason shy away from Stream? Stream and GIO look functionally the same. It looks like IPC (stream) is fairly "new" while SYS/BIOS (and I suspect GIO) has been out much longer.

    Anyway, thanks for all your help and patience.

    Marshall

  • Marshall,

    OK, great!  Thanks for the update. And for *your* patience in working thru this.

    I’d been trying to imagine a scenario where just adding the GIO function calls (but without calling them) could cause the Task create failures.  I was going to build a test case this afternoon to see if I could recreate it.  Now I’ll look at how the uninitialized Error_Block would cause the create failure, and look for a way to fix it, or at least document it.

    For GIO versus Stream… I don’t know the details, but from talking to those more familiar with the two, GIO is the recommendation.  I gather there are more people using GIO versus stream, and the internals are simpler.

    Scott