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.

IPC API is missing from C2000Ware 3.4 DriverLib

Other Parts Discussed in Thread: C2000WARE

Hello,

<Problem>

Linking fails when I try use functions such as IPC_registerInterrupt() etc. from...

C:\ti\c2000\C2000Ware_3_04_00_00\driverlib\f2837xd\driverlib\ccs\Debug\driverlib.lib

...in my project:

<Cause>

The following driverlib folder contains ipc.c and ipc.h

C:\ti\c2000\C2000Ware_3_04_00_00\driverlib\f2837xd\driverlib

But the driverlib project located at....

C:\ti\c2000\C2000Ware_3_04_00_00\driverlib\f2837xd\driverlib\ccs

...does not have ipc.c as a linked resource.

<Question>

Why is ipc.c missing from C2000Ware 3.4 driverlib.lib please?

Thank you.

  • Looks like the IPC is work in progress and somehow ipc.c got released but not built into the library. For example, the function  IPC_registerInterrupt() doesn't actually do anything with the ISR pointer pfnHandler.:

    void IPC_registerInterrupt(IPC_Type_t ipcType, uint32_t ipcInt,
                               void (*pfnHandler)(void))
    {
        //
        // Check for arguments
        //


        //
        // Get the corresponding interrupt number
        //
        uint32_t intNum = IPC_Instance[ipcType].IPC_IntNum[ipcInt];

        //
        // Register the interrupt handler
        //


        //
        // Enable the interrupt
        //
        Interrupt_enable(intNum);
    }

  • Kier,

    You are correct. It was not completely implemented and tested on F2837xD device, and that was the reason it was not included in Driverlib.lib. I have a local copy you can take a look but again it has not gone through system test, so if there is some issue you will have to debug yourself.

    Otherwise, you can stay with bitfield based implementation.

    You can copy ipc.c and ipc.h in device folder of your project.

    //###########################################################################
    //
    // FILE:   ipc.c
    //
    //
    //###########################################################################
    // $TI Release: F2837xD Support Library v3.12.00.00 $
    // $Release Date: Fri Feb 12 19:03:23 IST 2021 $
    // $Copyright:
    // Copyright (C) 2013-2021 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //###########################################################################
    
    #include "ipc.h"
    
    //
    // Macros internal to the IPC driver
    //
    
    #define IPC_REG_BOOTSTS_OFFSET             IPC_O_BOOTSTS
    
    #define IPC_ADDR_OFFSET_NOCHANGE           2U
    #define IPC_ADDR_OFFSET_MUL2               4U
    #define IPC_ADDR_OFFSET_DIV2               1U
    
    #define IPC_ADDR_OFFSET_CORR(addr, corr)  (((addr) * (corr)) / 2U)
    
    #if IPC_MSGQ_SUPPORT == 1U
    
    //
    // Global Circular Buffer Definitions
    //
    #pragma DATA_SECTION(IPC_CPU1_To_CPU2_PutBuffer, "PUTBUFFER")
    #pragma DATA_SECTION(IPC_CPU1_To_CPU2_GetBuffer, "GETBUFFER")
    
    //
    // IPC_CPU1_To_CPU2_PutBuffer acts as IPC_CPU2_To_CPU1_GetBuffer and
    // IPC_CPU1_To_CPU2_GetBuffer acts as IPC_CPU2_To_CPU1_PutBuffer
    //
    IPC_PutBuffer_t IPC_CPU1_To_CPU2_PutBuffer;
    IPC_GetBuffer_t IPC_CPU1_To_CPU2_GetBuffer;
    
    #endif
    
    const IPC_Instance_t IPC_Instance[IPC_TOTAL_NUM] =
    {
         /* IPC_CPU1_L_CPU2_R */
         {
          .IPC_Flag_Ctr_Reg   = (volatile IPC_Flag_Ctr_Reg_t *) IPC_CPUXTOCPUX_BASE,
          .IPC_SendCmd_Reg    = (volatile IPC_SendCmd_Reg_t *)
                                (IPC_CPUXTOCPUX_BASE + IPC_O_CPU1TOCPU2IPCSENDCOM),
          .IPC_RecvCmd_Reg    = (volatile IPC_RecvCmd_Reg_t *)
                                (IPC_CPUXTOCPUX_BASE + IPC_O_CPU2TOCPU1IPCRECVCOM),
          .IPC_Boot_Pump_Reg  = (volatile IPC_Boot_Pump_Reg_t *)
                                (IPC_CPUXTOCPUX_BASE + IPC_REG_BOOTSTS_OFFSET),
          .IPC_IntNum         = {INT_CIPC0, INT_CIPC1, INT_CIPC2, INT_CIPC3,
                                 0U, 0U, 0U, 0U},
          .IPC_MsgRam_LtoR    = CPU1TOCPU2MSGRAM0_BASE,
          .IPC_MsgRam_RtoL    = CPU2TOCPU1MSGRAM0_BASE,
          .IPC_Offset_Corr    = IPC_ADDR_OFFSET_NOCHANGE
    #if IPC_MSGQ_SUPPORT == 1U
          ,
          .IPC_PutBuffer      = &IPC_CPU1_To_CPU2_PutBuffer,
          .IPC_GetBuffer      = &IPC_CPU1_To_CPU2_GetBuffer
    #endif
         },
    
         /* IPC_CPU2_L_CPU1_R */
         {
          .IPC_Flag_Ctr_Reg   = (volatile IPC_Flag_Ctr_Reg_t *) IPC_CPUXTOCPUX_BASE,
          .IPC_SendCmd_Reg    = (volatile IPC_SendCmd_Reg_t *)
                                (IPC_CPUXTOCPUX_BASE + IPC_O_CPU2TOCPU1IPCSENDCOM),
          .IPC_RecvCmd_Reg    = (volatile IPC_RecvCmd_Reg_t *)
                                (IPC_CPUXTOCPUX_BASE + IPC_O_CPU1TOCPU2IPCRECVCOM),
          .IPC_Boot_Pump_Reg  = (volatile IPC_Boot_Pump_Reg_t *)
                                (IPC_CPUXTOCPUX_BASE + IPC_REG_BOOTSTS_OFFSET),
          .IPC_IntNum         = {INT_CIPC0, INT_CIPC1, INT_CIPC2, INT_CIPC3,
                                 0U, 0U, 0U, 0U},
          .IPC_MsgRam_LtoR    = CPU2TOCPU1MSGRAM0_BASE,
          .IPC_MsgRam_RtoL    = CPU1TOCPU2MSGRAM0_BASE,
          .IPC_Offset_Corr    = IPC_ADDR_OFFSET_NOCHANGE
    #if IPC_MSGQ_SUPPORT == 1U
          ,
          .IPC_PutBuffer      = (IPC_PutBuffer_t *)&IPC_CPU1_To_CPU2_GetBuffer,
          .IPC_GetBuffer      = (IPC_GetBuffer_t *)&IPC_CPU1_To_CPU2_PutBuffer
    #endif
         },
    
    };
    
    //*****************************************************************************
    //
    // IPC_sendCommand
    //
    //*****************************************************************************
    bool IPC_sendCommand(IPC_Type_t ipcType, uint32_t flags, bool addrCorrEnable,
                         uint32_t command, uint32_t addr, uint32_t data)
    {
        bool ret;
    
        //
        // Check whether the flags are not busy
        //
        if((IPC_Instance[ipcType].IPC_Flag_Ctr_Reg->IPC_FLG & flags) == 0U)
        {
            ret = true;
    
            if(addrCorrEnable)
            {
                //
                // Update the command registers. ADDR register holds the offset
                // from the base address of the MSG RAM
                //
                IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDCOM  = command;
                IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDDATA = data;
                IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDADDR =
                                addr - IPC_Instance[ipcType].IPC_MsgRam_LtoR;
            }
            else
            {
                //
                // Update the command registers. addr param remains as is.
                //
                IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDCOM  = command;
                IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDDATA = data;
                IPC_Instance[ipcType].IPC_SendCmd_Reg->IPC_SENDADDR = addr;
            }
    
            //
            // Set the flags to indicate the remote core
            //
            IPC_Instance[ipcType].IPC_Flag_Ctr_Reg->IPC_SET = flags;
        }
        else
        {
            ret = false;
        }
    
        return(ret);
    }
    
    //*****************************************************************************
    //
    // IPC_readCommand
    //
    //*****************************************************************************
    bool IPC_readCommand(IPC_Type_t ipcType, uint32_t flags, bool addrCorrEnable,
                         uint32_t *command, uint32_t *addr, uint32_t *data)
    {
        bool ret;
        uint32_t addrReg;
    
        //
        // Check whether the flags are not empty
        //
        if((IPC_Instance[ipcType].IPC_Flag_Ctr_Reg->IPC_STS & flags) != 0U)
        {
            ret = true;
    
            //
            // Read the command registers
            //
            *command   = IPC_Instance[ipcType].IPC_RecvCmd_Reg->IPC_RECVCOM;
            addrReg    = IPC_Instance[ipcType].IPC_RecvCmd_Reg->IPC_RECVADDR;
            *data      = IPC_Instance[ipcType].IPC_RecvCmd_Reg->IPC_RECVDATA;
    
            if(addrCorrEnable)
            {
                //
                // Calculate the address form the offset
                //
                *addr = IPC_Instance[ipcType].IPC_MsgRam_RtoL +
                        IPC_ADDR_OFFSET_CORR(addrReg,
                                        IPC_Instance[ipcType].IPC_Offset_Corr);
    
            }
            else
            {
                *addr = addrReg;
            }
    
        }
        else
        {
            ret = false;
        }
    
        return(ret);
    }
    
    
    //*****************************************************************************
    //
    // IPC_registerInterrupt
    //
    //*****************************************************************************
    void IPC_registerInterrupt(IPC_Type_t ipcType, uint32_t ipcInt,
                               void (*pfnHandler)(void))
    {
        //
        // Check for arguments
        //
    
    
        //
        // Get the corresponding interrupt number
        //
        uint32_t intNum = IPC_Instance[ipcType].IPC_IntNum[ipcInt];
    
        //
        // Register the interrupt handler
        //
        Interrupt_register(intNum, pfnHandler);
    
    
        //
        // Enable the interrupt
        //
        Interrupt_enable(intNum);
    }
    
    //*****************************************************************************
    //
    // IPC_unregisterInterrupt
    //
    //*****************************************************************************
    void IPC_unregisterInterrupt(IPC_Type_t ipcType, uint32_t ipcInt)
    {
        //
        // Check for arguments
        //
    
    
        //
        // Get the corresponding interrupt number
        //
        uint32_t intNum = IPC_Instance[ipcType].IPC_IntNum[ipcInt];
    
        //
        // Disable the interrupt.
        //
        Interrupt_disable(intNum);
    
        //
        // Unregister the interrupt handler.
        //
    
    }
    
    #if IPC_MSGQ_SUPPORT == 1U
    //*****************************************************************************
    //
    // IPCinitMessageQueue
    //
    //*****************************************************************************
    void IPC_initMessageQueue(IPC_Type_t ipcType,
                             volatile IPC_MessageQueue_t *msgQueue,
                             uint32_t ipcInt_L, uint32_t ipcInt_R)
    {
        //
        // Check for arguments
        //
        ASSERT(msgQueue != NULL);
        ASSERT(ipcInt_L < IPC_NUM_OF_INTERRUPTS);
        ASSERT(ipcInt_R < IPC_NUM_OF_INTERRUPTS);
    
        IPC_PutBuffer_t *putBuffer = IPC_Instance[ipcType].IPC_PutBuffer;
        IPC_GetBuffer_t *getBuffer = IPC_Instance[ipcType].IPC_GetBuffer;
    
        //
        // L->R Put Buffer and Index Initialization
        //
        msgQueue->PutBuffer     = putBuffer->Buffer[ipcInt_R];
        msgQueue->PutWriteIndex = &(putBuffer->PutWriteIndex[ipcInt_R]);
        msgQueue->GetReadIndex  = &(putBuffer->GetReadIndex[ipcInt_L]);
        msgQueue->PutFlag       = (uint32_t)1U << ipcInt_R;
    
        //
        // L->R Get Buffer and Index Initialization
        //
        msgQueue->GetBuffer     = getBuffer->Buffer[ipcInt_L];
        msgQueue->GetWriteIndex = &(getBuffer->GetWriteIndex[ipcInt_L]);
        msgQueue->PutReadIndex  = &(getBuffer->PutReadIndex[ipcInt_R]);
    
        //
        // Initialize PutBuffer WriteIndex = 0 and GetBuffer ReadIndex = 0
        //
        *(msgQueue->PutWriteIndex) = 0U;
        *(msgQueue->GetReadIndex)  = 0U;
    }
    
    //*****************************************************************************
    //
    // IPC_sendMessageToQueue
    //
    //*****************************************************************************
    bool IPC_sendMessageToQueue(IPC_Type_t ipcType,
                               volatile IPC_MessageQueue_t *msgQueue,
                               bool addrCorrEnable, IPC_Message_t *msg, bool block)
    {
        //
        // Check for arguments
        //
        ASSERT(msgQueue != NULL);
        ASSERT(msg != NULL);
    
        uint16_t writeIndex;
        uint16_t readIndex;
        uint16_t ret = true;
    
        writeIndex = *(msgQueue->PutWriteIndex);
        readIndex  = *(msgQueue->PutReadIndex);
    
        //
        // Wait until Put Buffer slot is free
        //
        while(((writeIndex + 1U) & IPC_MAX_BUFFER_INDEX) == readIndex)
        {
            //
            // If designated as a "Blocking" function, and Put buffer is full,
            // return immediately with fail status.
            //
            if(!block)
            {
                ret = false;
                break;
            }
    
            readIndex = *(msgQueue->PutReadIndex);
        }
    
        if(ret != false)
        {
            //
            // When slot is free, Write Message to PutBuffer, update PutWriteIndex,
            // and set the CPU IPC INT Flag
            //
            msgQueue->PutBuffer[writeIndex] = *msg;
    
            if(addrCorrEnable)
            {
                msgQueue->PutBuffer[writeIndex].address -=
                    IPC_Instance[ipcType].IPC_MsgRam_LtoR;
            }
    
            writeIndex = (writeIndex + 1U) & IPC_MAX_BUFFER_INDEX;
            *(msgQueue->PutWriteIndex) = writeIndex;
    
            IPC_setFlagLtoR(ipcType, msgQueue->PutFlag);
        }
    
        return(ret);
    }
    
    //*****************************************************************************
    //
    // IPC_readMessageFromQueue
    //
    //*****************************************************************************
    bool IPC_readMessageFromQueue(IPC_Type_t ipcType,
                                volatile IPC_MessageQueue_t *msgQueue,
                                bool addrCorrEnable, IPC_Message_t *msg, bool block)
    {
        //
        // Check for arguments
        //
        ASSERT(msgQueue != NULL);
        ASSERT(msg != NULL);
    
        uint16_t writeIndex;
        uint16_t readIndex;
        uint16_t ret = true;
    
        writeIndex = *(msgQueue->GetWriteIndex);
        readIndex  = *(msgQueue->GetReadIndex);
    
        //
        // Loop while GetBuffer is empty
        //
        while(writeIndex == readIndex)
        {
            //
            // If designated as a "Blocking" function, and Get buffer is empty,
            // return immediately with fail status.
            //
            if(!block)
            {
                ret = false;
                break;
            }
    
            writeIndex = *(msgQueue->GetWriteIndex);
        }
    
        if(ret != false)
        {
            //
            // If there is a message in GetBuffer, Read Message and update
            // the ReadIndex
            //
            *msg = msgQueue->GetBuffer[readIndex];
            if(addrCorrEnable)
            {
                msg->address = IPC_Instance[ipcType].IPC_MsgRam_RtoL +
                               IPC_ADDR_OFFSET_CORR(msg->address,
                                            IPC_Instance[ipcType].IPC_Offset_Corr);
            }
    
            readIndex = (readIndex + 1U) & IPC_MAX_BUFFER_INDEX;
            *(msgQueue->GetReadIndex) = readIndex;
        }
    
        return(ret);
    }
    #endif
    
    ipc.h

  • Thank you Santosh. For now I will attempt to use your files or bit-field access.

    I infer that IPC will be available "officially" in the next C2000Ware DriverLib, would that be correct?

  • Yes, we are planning to include in Q1,2022 release.