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/TMS320F28379D: SYS/BIOS sci rx interrupt by integrating driverlib

Part Number: TMS320F28379D
Other Parts Discussed in Thread: C2000WARE, SYSBIOS

Tool/software: TI-RTOS

Hi,

I want to implement a little SYS/BIOS and C2000Ware project that prints in console a char received by SCI comms. And I want to configure an RX SCI interruption. In the meantime, there are 2 tasks which simply print through console, every second, a string. To do so, I have integrated driverlib into the SYS/BIOS project. And I have copied big part of the code found in driverlib sci loopback interrupts example.

My code is as follows:

#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>

#include "c2000ware/device.h"

#define TASK_SCI_BASE       SCIB_BASE

Void task1(UArg arg1, UArg arg2);

/* Counter incremented by timer interrupt */
volatile UInt tickCount = 0;

/*
 *  ======== main ========
 */
Int main()
{
    Task_Params task_prms;
    Error_Block eb;

    /*
     * Print "Hello world" to a log buffer. 
     */
    System_printf("START\r\n");
    System_flush();

    Error_init(&eb);
    Task_Params_init(&task_prms);
    task_prms.stackSize = 1024;
    task_prms.priority = 15;
    Task_create(task1, &task_prms, &eb);

    /* 
     * Start BIOS.
     * Begins task scheduling.
     */
    BIOS_start();    /* does not return */
    return(0);
}

//
// sciaRXFIFOISR - SCIA Receive FIFO ISR
//
__interrupt void sciRXFIFOISR(void)
{
    uint16_t a[10];

    SCI_readCharArray(TASK_SCI_BASE, a, 1);
    a[1] = '\0';

    System_printf("a = %s\r\n", a);
    System_flush();

    SCI_clearOverflowStatus(TASK_SCI_BASE);

    SCI_clearInterruptStatus(TASK_SCI_BASE, SCI_INT_RXFF);

    // Issue PIE ack
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

void initComms(void) {
    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Setup GPIO by disabling pin locks and enabling pullups
    //
    Device_initGPIO();

    //
    // GPIO28 is the SCI Rx pin.
    //
    GPIO_setMasterCore(71, GPIO_CORE_CPU1);
    GPIO_setPinConfig(GPIO_71_SCIRXDB);
    GPIO_setDirectionMode(71, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(71, GPIO_PIN_TYPE_STD);
    GPIO_setQualificationMode(71, GPIO_QUAL_ASYNC);

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    //
    Interrupt_register(INT_SCIB_RX, sciRXFIFOISR);

    //
    // 8 char bits, 1 stop bit, no parity. Baud rate is 9600.
    //
    SCI_setConfig(TASK_SCI_BASE, DEVICE_LSPCLK_FREQ, 115200, (SCI_CONFIG_WLEN_8 |
                                                        SCI_CONFIG_STOP_ONE |
                                                        SCI_CONFIG_PAR_NONE));
    SCI_enableModule(TASK_SCI_BASE);
    SCI_resetChannels(TASK_SCI_BASE);
    SCI_enableFIFO(TASK_SCI_BASE);

    //
    // RX and TX FIFO Interrupts Enabled
    //
    SCI_enableInterrupt(TASK_SCI_BASE, SCI_INT_RXFF);
    SCI_disableInterrupt(TASK_SCI_BASE, SCI_INT_RXERR);

    SCI_setFIFOInterruptLevel(TASK_SCI_BASE, SCI_FIFO_TX0, SCI_FIFO_RX1);
    SCI_performSoftwareReset(TASK_SCI_BASE);

    SCI_resetTxFIFO(TASK_SCI_BASE);
    SCI_resetRxFIFO(TASK_SCI_BASE);

#ifdef AUTOBAUD
    //
    // Perform an autobaud lock.
    // SCI expects an 'a' or 'A' to lock the baud rate.
    //
    SCI_lockAutobaud(TASK_SCI_BASE);
#endif

    Interrupt_enable(INT_SCIB_RX);
    Interrupt_enable(INT_SCIB_TX);

    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;
}

Void task2(UArg arg1, UArg arg2) {
    initComms();

    while (TRUE) {
        System_printf("Task 2\r\n");
        System_flush();

        Task_sleep(1000);
    }
}

Void task1(UArg arg1, UArg arg2) {
    Task_Params task_prms;
    Error_Block eb;

    Error_init(&eb);
    Task_Params_init(&task_prms);
    task_prms.stackSize = 1024;
    task_prms.priority = 15;
    Task_create(task2, &task_prms, &eb);

    while (TRUE) {
        System_printf("Task 1\r\n");
        System_flush();

        Task_sleep(1000);
    }
}

The problem is that the tasks which print a simple string each second get both stucked at instruction:

Task_sleep(1000);

And if I comment next line, they don't get stuck:

initComms();

Debugging, I have checked that within initComms() function the function which makes the 2 other tasks not work is:

Interrupt_initModule();

And I have checked the code of this function and the next lines are responsible for getting the other 2 tasks stucked at Task_sleep() function:

IER = 0x0000U;
IFR = 0x0000U;

I guess this driverlib code is conflictive with my app.cfg, so please find it bellow:

var Defaults = xdc.useModule('xdc.runtime.Defaults');
var Diags = xdc.useModule('xdc.runtime.Diags');
var Error = xdc.useModule('xdc.runtime.Error');
var Log = xdc.useModule('xdc.runtime.Log');
var LoggerBuf = xdc.useModule('xdc.runtime.LoggerBuf');
var Main = xdc.useModule('xdc.runtime.Main');
var Memory = xdc.useModule('xdc.runtime.Memory')
var SysMin = xdc.useModule('xdc.runtime.SysMin');
var System = xdc.useModule('xdc.runtime.System');
var Text = xdc.useModule('xdc.runtime.Text');

var BIOS = xdc.useModule('ti.sysbios.BIOS');
var Clock = xdc.useModule('ti.sysbios.knl.Clock');
var Swi = xdc.useModule('ti.sysbios.knl.Swi');
var Task = xdc.useModule('ti.sysbios.knl.Task');
var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');

var Hwi = xdc.useModule('ti.sysbios.family.c28.Hwi');

var Boot = xdc.useModule('ti.catalog.c2800.initF2837x.Boot');

/*
 * Uncomment this line to globally disable Asserts.
 * All modules inherit the default from the 'Defaults' module.  You
 * can override these defaults on a per-module basis using Module.common$. 
 * Disabling Asserts will save code space and improve runtime performance.
Defaults.common$.diags_ASSERT = Diags.ALWAYS_OFF;
 */

/*
 * Uncomment this line to keep module names from being loaded on the target.
 * The module name strings are placed in the .const section. Setting this
 * parameter to false will save space in the .const section.  Error and
 * Assert messages will contain an "unknown module" prefix instead
 * of the actual module name.
Defaults.common$.namedModule = false;
 */

/*
 * Minimize exit handler array in System.  The System module includes
 * an array of functions that are registered with System_atexit() to be
 * called by System_exit().
 */
System.maxAtexitHandlers = 4;       

/* 
 * Uncomment this line to disable the Error print function.  
 * We lose error information when this is disabled since the errors are
 * not printed.  Disabling the raiseHook will save some code space if
 * your app is not using System_printf() since the Error_print() function
 * calls System_printf().
Error.raiseHook = null;
 */

/* 
 * Uncomment this line to keep Error, Assert, and Log strings from being
 * loaded on the target.  These strings are placed in the .const section.
 * Setting this parameter to false will save space in the .const section.
 * Error, Assert and Log message will print raw ids and args instead of
 * a formatted message.
Text.isLoaded = false;
 */

/*
 * Uncomment this line to disable the output of characters by SysMin
 * when the program exits.  SysMin writes characters to a circular buffer.
 * This buffer can be viewed using the SysMin Output view in ROV.
SysMin.flushAtExit = false;
 */

/*
 * The BIOS module will create the default heap for the system.
 * Specify the size of this default heap.
 */
BIOS.heapSize = 0x1000;

/*
 * Build a custom SYS/BIOS library from sources.
 */
BIOS.libType = BIOS.LibType_Custom;

/* System stack size (used by ISRs and Swis) */
Program.stack = 0x100;

/* Circular buffer size for System_printf() */
SysMin.bufSize = 0x200;

/* 
 * Create and install logger for the whole system
 */
var loggerBufParams = new LoggerBuf.Params();
loggerBufParams.numEntries = 32;
var logger0 = LoggerBuf.create(loggerBufParams);
Defaults.common$.logger = logger0;
Main.common$.diags_INFO = Diags.ALWAYS_ON;

System.SupportProxy = SysMin;

Boot.configureClocks = true;
Boot.configureFlashController = true;
BIOS.cpuFreq.lo = 200000000;
Clock.tickPeriod = 1000;
Boot.SYSCLKDIVSEL = 1;
Boot.OSCCLK = 20;
Boot.SPLLIMULT = 20;
Boot.SPLLFMULT = Boot.Fract_0;
Boot.OSCCLKSRCSEL = Boot.OscClk_XTAL;
Boot.disableWatchdog = true;
Boot.bootFromFlash = true;
Boot.configSharedRAMs = true;

Can anyone tell me what is going on and propose me solutions?

Thanks in advance!

Best regards,

Adria

  • Hi Adria,

    In SYS/BIOS for your interrupts, you should create a Hwi instead of calling the Interrupt driver functions. SYS/BIOS will handle initializing the PIE and vector table for you. Have you looked at the SYS/BIOS "PIE Interrupt Example" from the Resource Explorer (Classic) in CCS? It gives a good demonstration on how to configure a Hwi on the C28.

    Whitney
  • Hi Whitney,

    Yes I had looked at it, but I didn't know how to configure the Hwi to be triggered by SCI Rx. I have done it using driverlib (only SCI APIs and avoiding to use Interrupt APIs just as you said) and it works.

    Now I have 2 little problems:

    1. I cannot call SCI APIs directly from Hwi ISR, which makes me, for example, post an event from the Hwi ISR from which a Task is pending and then this Tasks executes the SCI lines I cannot execute from Hwi ISR. Those lines are:

    SCI_clearOverflowStatus(SCI_RX_INTERRUPT_SCI_BASE);
    SCI_clearInterruptStatus(SCI_RX_INTERRUPT_SCI_BASE, SCI_INT_RXFF);

    2. For each byte I receive, the ISR is called twice and I don't know why. Please find my SCI configuration code (using driverlib) to see if you can find why:

    Device_init();
    Device_initGPIO();
    GPIO_setMasterCore(71, GPIO_CORE_CPU1);
    GPIO_setPinConfig(GPIO_71_SCIRXDB);
    GPIO_setDirectionMode(71, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(71, GPIO_PIN_TYPE_STD);
    GPIO_setQualificationMode(71, GPIO_QUAL_ASYNC);
    SCI_setConfig(SCIB_BASE, DEVICE_LSPCLK_FREQ, 115200, (SCI_CONFIG_WLEN_8 |
                                                        SCI_CONFIG_STOP_ONE |
                                                        SCI_CONFIG_PAR_NONE));
    SCI_enableModule(SCIB_BASE);
    SCI_resetChannels(SCIB_BASE);
    SCI_enableFIFO(SCIB_BASE);
    SCI_enableInterrupt(SCIB_BASE, SCI_INT_RXFF);
    SCI_setFIFOInterruptLevel(SCIB_BASE, SCI_FIFO_TX0, SCI_FIFO_RX1);
    SCI_performSoftwareReset(SCIB_BASE);
    SCI_resetTxFIFO(SCIB_BASE);
    SCI_resetRxFIFO(SCIB_BASE);

    And also find my Hwi configuration code:

    Error_Block eb;
    Hwi_Params hwi_params;
    
    Hwi_Params_init(&hwi_params);
    hwi_params.arg = 98;
    hwi_params.enableAck = true;
    hwi_params.maskSetting = Hwi_MaskingOption_BITMASK;
    hwi_params.disableMask = 0x0;
    hwi_params.restoreMask = 0x0;
    Hwi_create(98, sciRXFIFOISR, &hwi_params, &eb);

    Finally, to read the data I use the next code:

    while (SCI_FIFO_RX0 != SCI_getRxFIFOStatus(SCIB_BASE)) {
        uint16_t byte = SCI_readCharNonBlocking(SCIB_BASE);
        Task_sleep(1);
    }

    Best regards,

    Adria

  • Hi,

    I found out why the ISR was being called twice per received byte. It was because I was executing first:

    SCI_clearOverflowStatus(SCIB_BASE);
    SCI_clearInterruptStatus(SCIB_BASE, SCI_INT_RXFF);

    And then I read the byte:

    while (SCI_FIFO_RX0 != SCI_getRxFIFOStatus(SCIB_BASE)) {
        uint16_t byte = SCI_readCharNonBlocking(SCIB_BASE);
        Task_sleep(1);
    }

    If I just read and then clear both the overflow status and the Interrupt status the ISR is called once per received byte.

    About the fact of not being able to execute SCI driverlib APIs within Hwi ISR, can you help me with that?

    Best regards,

    Adria

  • Hi,

    I didn't click on "This resolved my issue" on purpose. So, can you please mark it as unresolved or tell me how to do it? I haven't seen any option to do it.

    Best regards,

    Adria
  • Adria,

    Can you clarify your current state at the moment with respect to SYSBIOS? Seems like you made a first post then got things to somewhat work but was that in a SYSBIOS environment or not?

    If Interrupt_initModule() does the following:
    IER = 0x0000U;
    IFR = 0x0000U;

    That obviously would be a huge problem. Basically that is disabling all interrupts and clearing any interrupt that would have been flagged in the system. This would undo any interrupt cofiguration that SYSBIOS would have done.

    Dont call these APIs in initComms():
    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    //
    Interrupt_register(INT_SCIB_RX, sciRXFIFOISR);

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;
    --------------------------------------------------------------------------------------------
    Thes are probably ok to be called:

    Interrupt_enable(INT_SCIB_RX);
    Interrupt_enable(INT_SCIB_TX);

    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
    --------------------------------------------------------------------------------------------

    initComms should be called in main() or before main().

    You need to create a Hwi on the interrupt that you want to use (I think you said interrupt #28?) with the function sciRXFIFOISR()
    but remove the __interrupt keyword from the function declaration


    Judah

  • Hi Judah,

    Thanks for your answer.

    In the answer I marked as "Resolved my issue" (which wasn't on purpose and I would be thankful if some one told me how to undo it or just undo it itself) you can see how I already made work what you are saying right after Whitney's answer. I removed all calls to Interrupt module. Then 2 new problems emerged. One of them I solved it and the other one still exists.

    The problem is that I cannot call any SCI (from driverlib) API within the Hwi ISR. This makes me have to call SCI APIs from a different context than Hwi ISR (to read received bytes and clear SCI overflow status and interrupt flag). What I am doing now is to post an event within the Hwi ISR which wakes up a Task which does the SCI operations. But what if I need to do these operation within the Hwi ISR context? How can I do that?

    Best regards,

    Adria

  • There shouldn't be anything wrong with calling the SCI driver in the Hwi function. Why are you saying you can't? Do you get an error when you try it?

    Regarding the resolved status of the post, I don't know how to undo it--I'll have to ask some experts to find out if there's a way. The thread is still considered open since you continue to reply to it, so it's still in my support queue.

    Whitney
  • Adria,

    Thanks for clarifying that....Ok I see where you are at now.

    One thing you could try is....remove these 3 lines from your code. I'm not sure why you have it this way, but with these 3 lines
    when you are processing this interrupt, you've open up all interrupts to preempt it including yourself. Typically an interrupt
    should make itself when its running (This is the default BIOS behavior and should happen if you remove these 3 lines).

    hwi_params.maskSetting = Hwi_MaskingOption_BITMASK;
    hwi_params.disableMask = 0x0;
    hwi_params.restoreMask = 0x0;

    The other line that you ought to play around with is the acknowledge line. If you're acknowledging the interrupt in your ISR then
    you might not need this line.

    hwi_params.enableAck = true;

    I second Whitney, that SCI driver APIs should be callable from your BIOS ISR. I don't know what exactly those APIs are doing but
    typically driver APIs configure that hardware's registers and is not messing with the general Chip interrupt stuff which would be
    what BIOS is doing.
  • Hi,

    I tried to call SCI APIs from Hwi again and now I have no problem. I guess, when I had more mistakes (at the beginning of this thread) I just made it work by removing SCI code from Hwi and adding it in another task. And once all other errors were resolved I still though the SCI code within Hwi was a problem.

    So thank you guys!

    Best regards,

    Adria
  • Glad to hear it! Is the issue totally resolved now? Can I close the thread?

    Whitney
  • Hi Whitney,

    Sure!

    Adria