//#############################################################################
//
// FILE:  ipc_ex2_basic_cpu1_cpu3_multi_c29x1.c
//
// TITLE: SysConfig IPC example with interrupt
//
//! \addtogroup driver_dual_example_list
//! <h1> IPC basic message passing example with interrupt </h1>
//!
//! This example demonstrates how to configure IPC and pass information from
//! C29x1 to C29x3 core without message queues.
//!
//! When using CCS for debugging this Multi-core example, after launching the
//! debug session,
//!     - Connect to CPU1 and load only the c29x1.out.
//!     - After the program is loaded, run CPU1.
//!     - Once c29x1 configures and releases CPU3 out of reset, the program
//!     stops.
//!     - Connect to CPU3 target now. c29x3.out would have started execution
//!     as soon as it is released from reset.
//!     - In case of RAM configuration, restart the CPU3 target and load the
//!     symbols.
//!
//! \note For FLASH configuration, this example is run in FLASH BANKMODE2,
//! where CPU3 has access to FLASH (FRI-2). Refer to the Flash Plugin
//! documentation to know about changing FLASH BANKMODEs and more.
//! Additionally, the CPAx and CDAx RAMs are used for allocating various
//! RAM sections.
//!
//! \b External \b Connections \n
//!  - None.
//!
//! \b Watch \b Variables \n
//!  - pass
//!
//
//#############################################################################
// //
//	Copyright: Copyright (C) Texas Instruments Incorporated
//	All rights reserved not granted herein.
//
//  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.
//

//###########################################################################

//
// Included Files
//
#include "board.h"

//
// Defines
//
#define IPC_CMD_READ_MEM   0x1001

#define TEST_PASS          0x5555
#define TEST_FAIL          0xAAAA

uint32_t readData[10];

uint32_t pass;

#ifdef _FLASH
    #define CPU3_RESET_VECTOR   0x10401000U
    #define CPU3_NMI_VECTOR     0x10401040U
#else
    #define CPU3_RESET_VECTOR   0x20110000U
    #define CPU3_NMI_VECTOR     0x20110040U
#endif

#define IPC_CMD_READ_MEM   0x1001

#define TEST_PASS          0x5555
#define TEST_FAIL          0xAAAA
#define EPWM4_TIMER_TBPRD  2000U
#define EPWM4_MAX_CMPA     1950U
#define EPWM4_MIN_CMPA       50U
#define EPWM4_MAX_CMPB     1950U
#define EPWM4_MIN_CMPB       50U

#define EPWM5_TIMER_TBPRD  2000U
#define EPWM5_MAX_CMPA     1950U
#define EPWM5_MIN_CMPA       50U
#define EPWM5_MAX_CMPB     1950U
#define EPWM5_MIN_CMPB       50U

#define EPWM6_TIMER_TBPRD  2000U
#define EPWM6_MAX_CMPA      950U
#define EPWM6_MIN_CMPA       50U
#define EPWM6_MAX_CMPB     1950U
#define EPWM6_MIN_CMPB     1050U


#define EPWM_CMP_UP           1U
#define EPWM_CMP_DOWN         0U

//
// Globals
//
typedef struct
{
    uint32_t epwmModule;
    uint16_t epwmCompADirection;
    uint16_t epwmCompBDirection;
    uint16_t epwmTimerIntCount;
    uint16_t epwmMaxCompA;
    uint16_t epwmMinCompA;
    uint16_t epwmMaxCompB;
    uint16_t epwmMinCompB;
}epwmInformation;

//
// Globals to hold the ePWM information used in this example
//
epwmInformation epwm4Info;
epwmInformation epwm5Info;
epwmInformation epwm6Info;
//
// Function Prototypes
//
void initEPWM4(void);
void initEPWM5(void);
void initEPWM6(void);

__attribute__((interrupt("INT"))) void epwm4ISR(void);
__attribute__((interrupt("INT"))) void epwm5ISR(void);
__attribute__((interrupt("INT"))) void epwm6ISR(void);

volatile uint16_t epwm4Interrupt;
volatile uint16_t epwm5Interrupt;
volatile uint16_t epwm6Interrupt;

//
// Main
//
int main(void)
{
    int i;

    //
    // Initialize device clock, peripheral clocks and interrupts
    //
    Device_init();

    //
    // Initialize device clock and peripherals
    //
    epwm4Interrupt = 0;
    epwm5Interrupt = 0;
    epwm6Interrupt = 0;

    //
    // Initialize SysConfig Settings
    //
    Board_init();

    initEPWM4();
    initEPWM5();
    initEPWM6();

    //
    // Defines the address at which CPU3 Boots
    //
    SSU_configBootAddress(SSU_CPU3, (uint32_t)CPU3_RESET_VECTOR, SSU_LINK2);
    SSU_configNmiAddress(SSU_CPU3, CPU3_NMI_VECTOR, SSU_LINK2);

    //
    // Bring CPU3 out of reset. Wait for CPU3 to go out of reset.
    //
    SSU_controlCPUReset(SSU_CPU3, SSU_CORE_RESET_DEACTIVE);
    while(SysCtl_isCPU3Reset() == 0x1U);

    //
    // CPU3 is out of reset now. Connect to CPU3 and load the symbols.
    //
    ESTOP0;

    //
    // Clear any IPC flags if set already
    //
    IPC_clearFlagLtoR(IPC_CPU1_L_CPU3_R_CH0, IPC_FLAG_ALL);

    //
    // Synchronize both the cores.
    //
    IPC_sync(IPC_CPU1_L_CPU3_R_CH0, IPC_FLAG31);

    //
    // Enable PIPE Global Interrupt (for INTs and RTINTs) and INT enable in CPU.
    //
    ENINT;
    Interrupt_enableGlobal();

    //
    // Fill in the data to be sent
    //
    for(i=0; i<10; i++)
    {
        readData[i] = i;
    }

    //
    // Send a message without message queue
    // Length of the data to be read is passed as data.
    //
    IPC_sendCommand(IPC_CPU1_L_CPU3_R_CH0, IPC_FLAG0, IPC_CMD_READ_MEM,
                    (uint32_t)readData, 10);

    //
    // Wait for acknowledgment
    //
    IPC_waitForAck(IPC_CPU1_L_CPU3_R_CH0, IPC_FLAG0);

    //
    // Read response
    //
    if(IPC_getResponse(IPC_CPU1_L_CPU3_R_CH0) == TEST_PASS)
    {
        pass = 1;
    }
    else
    {
        pass = 0;
    }

    //
    // End of example. Loop forever
    //
    while(1);
}

//
// epwm4ISR - ePWM 1 ISR
//
void epwm4ISR(void)
{
    epwm4Interrupt++;

    //
    // Clear INT flag for this timer
    //
    EPWM_clearEventTriggerInterruptFlag(myEPWM4_BASE);
}

//
// epwm5ISR - ePWM 2 ISR
//
void epwm5ISR(void)
{
    epwm5Interrupt++;

    //
    // Clear INT flag for this timer
    //
    EPWM_clearEventTriggerInterruptFlag(myEPWM5_BASE);
}

//
// epwm6ISR - ePWM 3 ISR
//
void epwm6ISR(void)
{
    epwm6Interrupt++;

    //
    // Clear INT flag for this timer
    //
    EPWM_clearEventTriggerInterruptFlag(myEPWM6_BASE);
}

//
// initEPWM4 - Configure ePWM1
//
void initEPWM4()
{
    //
    // Information this example uses to keep track of the direction the
    // CMPA/CMPB values are moving, the min and max allowed values and
    // a pointer to the correct ePWM registers
    //
    epwm4Info.epwmCompADirection = EPWM_CMP_UP;
    epwm4Info.epwmCompBDirection = EPWM_CMP_DOWN;
    epwm4Info.epwmTimerIntCount = 0U;
    epwm4Info.epwmModule = myEPWM4_BASE;
    epwm4Info.epwmMaxCompA = EPWM4_MAX_CMPA;
    epwm4Info.epwmMinCompA = EPWM4_MIN_CMPA;
    epwm4Info.epwmMaxCompB = EPWM4_MAX_CMPB;
    epwm4Info.epwmMinCompB = EPWM4_MIN_CMPB;
}

//
// initEPWM5 - Configure ePWM2
//
void initEPWM5()
{
    //
    // Information this example uses to keep track of the direction the
    // CMPA/CMPB values are moving, the min and max allowed values and
    // a pointer to the correct ePWM registers
    //
    epwm5Info.epwmCompADirection = EPWM_CMP_UP;
    epwm5Info.epwmCompBDirection = EPWM_CMP_UP;
    epwm5Info.epwmTimerIntCount = 0U;
    epwm5Info.epwmModule = myEPWM5_BASE;
    epwm5Info.epwmMaxCompA = EPWM5_MAX_CMPA;
    epwm5Info.epwmMinCompA = EPWM5_MIN_CMPA;
    epwm5Info.epwmMaxCompB = EPWM5_MAX_CMPB;
    epwm5Info.epwmMinCompB = EPWM5_MIN_CMPB;
}

//
// initEPWM6 - Configure ePWM2
//
void initEPWM6()
{
    //
    // Information this example uses to keep track of the direction the
    // CMPA/CMPB values are moving, the min and max allowed values and
    // a pointer to the correct ePWM registers
    //
    epwm6Info.epwmCompADirection = EPWM_CMP_UP;
    epwm6Info.epwmCompBDirection = EPWM_CMP_UP;
    epwm6Info.epwmTimerIntCount = 0U;
    epwm6Info.epwmModule = myEPWM6_BASE;
    epwm6Info.epwmMaxCompA = EPWM6_MAX_CMPA;
    epwm6Info.epwmMinCompA = EPWM6_MIN_CMPA;
    epwm6Info.epwmMaxCompB = EPWM6_MAX_CMPB;
    epwm6Info.epwmMinCompB = EPWM6_MIN_CMPB;
}

//
// End of File
//