//###########################################################################
//
// FILE:   cpu01_to_cpu02_ipcdrivers_cpu01.c
//
// TITLE:  CPU01 to CPU02 IPC Driver TestExample
//
//! \addtogroup dual_example_list
//! <h1> CPU01 to CPU02 IPC Driver </h1>
//!
//! This example tests all of the basic read/write CPU01 to CPU02 IPC Driver
//! functions available in F2837xD_Ipc_Driver.c.
//! The CPU01 project sends commands to the CPU02 project, which then processes
//! the commands.
//! The CPU02 project responds to the commands sent from the CPU01 project.
//! Note that IPC INT0 and IPC INT1 are used for this example to process IPC
//! commands.
//!
//! \b  Watch \b Variables \b for \b CPU01 : \n
//!  - ErrorCount - Counts # of errors
//!  - pusCPU01BufferPt - Stores 256 16-bit words block to write to CPU02
//!  - pusCPU02BufferPt - Points to beginning of 256 word block received
//!                       back from CPU02
//!  - usWWord16 - 16-bit word to write to CPU02
//!  - ulWWord32 - 32-bit word to write to CPU02
//!  - usRWord16 - 16-bit word to read from CPU02
//!  - ulRWord32 - 32-bit word to read from CPU02
//!
//! \b  Watch \b Variables \b for \b CPU02 : \n
//!  - ErrorFlag  - Indicates an unrecognized command was sent from
//!                 CPU01 to CPU02.
//!
//
//###########################################################################
// $TI Release: F2837xD Support Library v210 $
// $Release Date: Tue Nov  1 14:46:15 CDT 2016 $
// $Copyright: Copyright (C) 2013-2016 Texas Instruments Incorporated -
//             http://www.ti.com/ ALL RIGHTS RESERVED $
//###########################################################################

//
// Included Files
//
#include "F28x_Project.h"
#include "F2837xD_Ipc_drivers.h"

//
// Defines
//
#define CPU02TOCPU01_PASSMSG  0x0003FBF4     // CPU02 to CPU01 MSG RAM offsets
                                             // for passing address
#define SETMASK_16BIT         0xFF00         // Mask for setting bits of
                                             // 16-bit word
#define CLEARMASK_16BIT       0xA5A5         // Mask for clearing bits of
                                             // 16-bit word
#define SETMASK_32BIT         0xFFFF0000     // Mask for setting bits of
                                             // 32-bit word
#define CLEARMASK_32BIT       0xA5A5A5A5     // Mask for clearing bits of
                                             // 32-bit word
#define GS0SARAM_START        0xC000         // Start of GS0 SARAM

//
// Globals
//

//
// At least 1 volatile global tIpcController instance is required when using
// IPC API Drivers.
//
volatile tIpcController g_sIpcController1;
volatile tIpcController g_sIpcController2;

volatile uint16_t ErrorFlag;
volatile uint16_t ErrorCount;

//
// Global variables used in this example to read/write data passed between
// CPU01 and CPU02
//
uint16_t usWWord16;
uint32_t ulWWord32;
uint16_t usRWord16;
uint32_t ulRWord32;
uint16_t usCPU01Buffer[256];

//
// Function Prototypes
//
void Error(void);
__interrupt void CPU02toCPU01IPC0IntHandler(void);
__interrupt void CPU02toCPU01IPC1IntHandler(void);

//
// Main
//
void
main(void)
{
    uint16_t counter;
    uint16_t *pusCPU01BufferPt;
    uint16_t *pusCPU02BufferPt;
    uint32_t *pulMsgRam ;

//
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F2837xD_SysCtrl.c file.
//
    InitSysCtrl();

//
// Step 2. Initialize GPIO:
// This example function is found in the F2837xD_SysCtrl.c file and
// illustrates how to set the GPIO to it's default state.
//
// InitGpio();  // Skipped for this example

//
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
//
    DINT;

//
// Initialize PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the F2837xD_PieCtrl.c file.
//
    InitPieCtrl();

//
// Disable CPU interrupts and clear all CPU interrupt flags:
//
    IER = 0x0000;
    IFR = 0x0000;

//
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example.  This is useful for debug purposes.
// The shell ISR routines are found in F2837xD_DefaultISR.c.
// This function is found in F2837xD_PieVect.c.
//
    InitPieVectTable();

//
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
//
    EALLOW;  // This is needed to write to EALLOW protected registers
    PieVectTable.IPC0_INT = &CPU02toCPU01IPC0IntHandler;
    PieVectTable.IPC1_INT = &CPU02toCPU01IPC1IntHandler;
    EDIS;    // This is needed to disable write to EALLOW protected registers

#ifdef _STANDALONE
#ifdef _FLASH
    //
    //  Send boot command to allow the CPU02 application to begin execution
    //
    IPCBootCPU2(C1C2_BROM_BOOTMODE_BOOT_FROM_FLASH);
#else
    //
    //  Send boot command to allow the CPU02 application to begin execution
    //
    IPCBootCPU2(C1C2_BROM_BOOTMODE_BOOT_FROM_RAM);
#endif
#endif

//
// Step 4. Initialize the Device Peripherals:
//
    ErrorFlag = 0;

    IPCInitialize (&g_sIpcController1, IPC_INT0, IPC_INT0);
    IPCInitialize (&g_sIpcController2, IPC_INT1, IPC_INT1);

//
// Step 5. User specific code, enable interrupts:
//

//
// Enable CPU INT1 which is connected to Upper PIE IPC INT0-3:
//
    IER |= M_INT1;

//
// Enable CPU2 to CPU1 IPC INTn in the PIE: Group 1 interrupts
//
    PieCtrlRegs.PIEIER1.bit.INTx13 = 1;    // CPU2 to CPU1 INT0
    PieCtrlRegs.PIEIER1.bit.INTx14 = 1;    // CPU2 to CPU1 INT1

//
// Enable global Interrupts and higher priority real-time debug events:
//
    EINT;   // Enable Global interrupt INTM
    ERTM;   // Enable Global realtime interrupt DBGM

//
// Initialize local variables
//
    pulMsgRam = (void *)CPU02TOCPU01_PASSMSG;
    pusCPU01BufferPt = (void *)GS0SARAM_START;
    pusCPU02BufferPt = (void *)(GS0SARAM_START + 256);
    ErrorCount = 0;

//
// Initialize all variables used in example.
//
    for(counter = 0; counter < 256; counter++)
    {
        usCPU01Buffer[counter] = ((counter<<8)+(~counter));
    }

    usWWord16 = 0x1234;
    ulWWord32 = 0xABCD5678;
    usRWord16 = 0;
    ulRWord32 = 0;

//
// Spin here until CPU02 has written variable addresses to pulMsgRam
//
    while(IpcRegs.IPCSTS.bit.IPC17 != 1)
    {
    }
    IpcRegs.IPCACK.bit.IPC17 = 1;

//
// 16 and 32-bit Data Writes
// Write 16-bit word to CPU02 16-bit write word variable.
//
    IPCLtoRDataWrite(&g_sIpcController1, pulMsgRam[0],(uint32_t)usWWord16,
                     IPC_LENGTH_16_BITS, ENABLE_BLOCKING,NO_FLAG);

//
// Read 16-bit word from CPU02 16-bit write word variable. Use IPC Flag 17 to
// check when read data is ready.
//
    IPCLtoRDataRead(&g_sIpcController1, pulMsgRam[0], &usRWord16,
                    IPC_LENGTH_16_BITS, ENABLE_BLOCKING,
                    IPC_FLAG17);

//
// Write 32-bit word to CPU02 32-bit write word variable.
//
    IPCLtoRDataWrite(&g_sIpcController1, pulMsgRam[1],ulWWord32,
                     IPC_LENGTH_32_BITS, ENABLE_BLOCKING,
                     NO_FLAG);

//
// Read 32-bit word from CPU02 32-bit write word variable. Use IPC Flag 18 to
// check when read data is ready.
//
    IPCLtoRDataRead(&g_sIpcController1, pulMsgRam[1], &ulRWord32,
                    IPC_LENGTH_32_BITS, ENABLE_BLOCKING,
                    IPC_FLAG18);

//
// Wait until read variables are ready (by checking IPC Response Flag is
// cleared). Then check Read var = Write var
//
    while(IpcRegs.IPCFLG.bit.IPC17)
    {
    }

    if(usWWord16 != usRWord16)
    {
        ErrorCount++;
    }

    while(IpcRegs.IPCFLG.bit.IPC18)
    {
    }

    if(ulWWord32 != ulRWord32)
    {
        ErrorCount++;
    }

//
// 16 and 32-bit Data Set Bits
// Set upper 8 bits in 16-bit write word variable location.
//
    IPCLtoRSetBits(&g_sIpcController1, pulMsgRam[0],(uint32_t)SETMASK_16BIT,
                   IPC_LENGTH_16_BITS,ENABLE_BLOCKING);

//
// Read 16-bit word from CPU02 16-bit write word variable. Use IPC Flag 17 to
// check when read data is ready.
//
    IPCLtoRDataRead(&g_sIpcController1, pulMsgRam[0], &usRWord16,
                    IPC_LENGTH_16_BITS, ENABLE_BLOCKING,IPC_FLAG17);

//
// Set upper 16 bits in 32-bit write word variable location.
//
    IPCLtoRSetBits(&g_sIpcController1, pulMsgRam[1], SETMASK_32BIT,
                   IPC_LENGTH_32_BITS,ENABLE_BLOCKING);

//
// Read 32-bit word from CPU02 32-bit write word variable. Use IPC Flag 18 to
// check when read data is ready.
//
    IPCLtoRDataRead(&g_sIpcController1, pulMsgRam[1], &ulRWord32,
                    IPC_LENGTH_32_BITS, ENABLE_BLOCKING,IPC_FLAG18);

//
// Wait until read variables are ready (by checking IPC Response Flag is
// cleared). Then check correct bits are set.
//
    while(IpcRegs.IPCFLG.bit.IPC17)
    {
    }

    if(usRWord16 != (usWWord16 | SETMASK_16BIT))
    {
        ErrorCount++;
    }

    while(IpcRegs.IPCFLG.bit.IPC18)
    {
    }

    if(ulRWord32 != (ulWWord32 | SETMASK_32BIT))
    {
        ErrorCount++;
    }

//
// 16 and 32-bit Data Clear Bits
// Clear alternating bits in 16-bit write word variable location
//
    IPCLtoRClearBits(&g_sIpcController1, pulMsgRam[0],(uint32_t)CLEARMASK_16BIT,
                     IPC_LENGTH_16_BITS,ENABLE_BLOCKING);

//
// Read 16-bit word from CPU02 16-bit write word variable. Use IPC Flag 17 to
// check when read data is ready.
//
    IPCLtoRDataRead(&g_sIpcController1, pulMsgRam[0], &usRWord16,
                    IPC_LENGTH_16_BITS, ENABLE_BLOCKING,IPC_FLAG17);

//
// Clear alternating bits in 32-bit write word variable location
//
    IPCLtoRClearBits(&g_sIpcController1, pulMsgRam[1],(uint32_t)CLEARMASK_32BIT,
                     IPC_LENGTH_32_BITS,ENABLE_BLOCKING);

//
// Read 16-bit word from CPU02 32-bit write word variable. Use IPC Flag 18 to
// check when read data is ready.
//
    IPCLtoRDataRead(&g_sIpcController1, pulMsgRam[1], &ulRWord32,
                    IPC_LENGTH_32_BITS, ENABLE_BLOCKING,IPC_FLAG18);

//
// Wait until read variables are ready (by checking IPC Response Flag is
// cleared). Then check correct bits are clear.
//
    while(IpcRegs.IPCFLG.bit.IPC17)
    {
    }

    if(usRWord16 != ((usWWord16 | SETMASK_16BIT) & (~CLEARMASK_16BIT)))
    {
        ErrorCount++;
    }

    while(IpcRegs.IPCFLG.bit.IPC18)
    {
    }

    if(ulRWord32  != ((ulWWord32 | SETMASK_32BIT) & (~CLEARMASK_32BIT)))
    {
        ErrorCount++;
    }

//
// Data Block Writes
//

//
// Request Memory Access to GS0 SARAM for CPU01
// Clear bits to let CPU01 own GS0
//
    if((MemCfgRegs.GSxMSEL.bit.MSEL_GS0) == 1)
    {
        EALLOW;
        MemCfgRegs.GSxMSEL.bit.MSEL_GS0 = 0;
        EDIS;
    }

//
// Write a block of data from CPU01 to GS0 shared RAM which is then written to
// an CPU02 address.
//
    for(counter = 0; counter < 256; counter++)
    {
        pusCPU01BufferPt[counter] = usCPU01Buffer[counter];
    }

    IPCLtoRBlockWrite(&g_sIpcController2, pulMsgRam[2],
                      (uint32_t)pusCPU01BufferPt, 256,
                      IPC_LENGTH_16_BITS,ENABLE_BLOCKING);

//
// Give Memory Access to GS0 SARAM to CPU02
//
    while(!(MemCfgRegs.GSxMSEL.bit.MSEL_GS0))
    {
        EALLOW;
        MemCfgRegs.GSxMSEL.bit.MSEL_GS0 = 1;
        EDIS;
    }

//
// Read data back from CPU02.
//
    IPCLtoRBlockRead(&g_sIpcController2, pulMsgRam[2],
                     (uint32_t)pusCPU02BufferPt, 256,
                     ENABLE_BLOCKING,IPC_FLAG17);

//
// Wait until read data is ready (by checking IPC Response Flag is cleared).
// Then check for correct data.
//
    while(IpcRegs.IPCFLG.bit.IPC17)
    {
    }

    for(counter = 0; counter <256; counter++)
    {
        if(usCPU01Buffer[counter] != pusCPU01BufferPt[counter])
        {
            ErrorFlag = 1;
        }
    }

    if (ErrorFlag == 1)
    {
        ErrorCount++;
    }

//
// Check Function Call Function
//

//
// Call FunctionCall() function on CPU02 with a dummy parameter of "0"(i.e. no
// parameter).
//
    IPCLtoRFunctionCall(&g_sIpcController1, pulMsgRam[3], 0, ENABLE_BLOCKING);

//
// Read status variable to check if function was entered. Use IPC Flag 17 to
// check when read data is ready.
//
    IPCLtoRDataRead(&g_sIpcController1, pulMsgRam[5], &usRWord16,
                    IPC_LENGTH_16_BITS, ENABLE_BLOCKING,
                    IPC_FLAG17);

//
// Call FunctionCall() function on CPU02 with a parameter of "0x12345678".
//
    IPCLtoRFunctionCall(&g_sIpcController1, pulMsgRam[4], 0x12345678,
                        ENABLE_BLOCKING);

//
// Read status variable to check if function was entered. Use IPC Flag 18 to
// check when read data is ready.
//
    IPCLtoRDataRead(&g_sIpcController1, pulMsgRam[5], &ulRWord32,
                    IPC_LENGTH_32_BITS, ENABLE_BLOCKING,
                    IPC_FLAG18);

//
// Wait until read data is ready (by checking IPC Response Flag is cleared).
// Then check status variables to see if function was entered.
//
    while(IpcRegs.IPCFLG.bit.IPC17)
    {
    }

    if(usRWord16 != 1)
    {
        ErrorCount++;
    }

    while(IpcRegs.IPCFLG.bit.IPC18)
    {
    }

    if(ulRWord32 != 0x12345678)
    {
        ErrorCount++;
    }

    if(ErrorCount != 0)
    {
        ESTOP0;
    }

    for(;;)
    {
        //
        // When Complete, Loop Forever here.
        //
    }
}

//
// CPU02toCPU01IPC0IntHandler - Handles writes into CPU01 addresses as a
//                              result of read commands to the CPU02.
//
__interrupt void CPU02toCPU01IPC0IntHandler (void)
{
    tIpcMessage sMessage;

    //
    // Continue processing messages as long as CPU01 to CPU02
    // GetBuffer1 is full
    //
    while(IpcGet(&g_sIpcController1, &sMessage,
                 DISABLE_BLOCKING) != STATUS_FAIL)
    {
        switch (sMessage.ulcommand)
        {
            case IPC_DATA_WRITE:
                IPCRtoLDataWrite(&sMessage);
                break;
            default:
                ErrorFlag = 1;
                break;
        }
    }

    //
    // Acknowledge IPC INT0 Flag and PIE to receive more interrupts
    //
    IpcRegs.IPCACK.bit.IPC0 = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}

//
// CPU02toCPU01IPC1IntHandler - Should never reach this ISR. This is an
//                              optional placeholder for g_sIpcController2.
//
__interrupt void CPU02toCPU01IPC1IntHandler (void)
{
    //
    // Should never reach here - Placeholder for Debug
    //
    // Acknowledge IPC INT1 Flag and PIE to receive more interrupts
    //
    IpcRegs.IPCACK.bit.IPC1 = 1;
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}

//
// End of file
//
