// TI Release: 28xx eCAN programming example
// Release Date: Fri Aug 4 2017
// Copyright:
// Copyright (C) 2017 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.
// 

/*********************************************************************
* Filename: RXINT_A.c                                               
*                                                                    
* Description: This is a simple example of how data may be received  	
* using interrupts. It also illustrates the ability of the CAN module
* to service multiple interrupts  automatically. 

*
*********************************************************************/

//
// Included Files
//
#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File

// Prototype statements for functions found within this file.

interrupt void eCAN0INT_ISR(void);
interrupt void eCAN1INT_ISR(void);

// Variable declarations

long    int0count = 0;		// Counter to track the # of level 0 interrupts
long    int1count = 0;	    // Counter to track the # of level 1 interrupts
long    i;
long    RXCOUNT = 0;
int	    MIV = 0; // Stores the mailbox # that needs to be serviced.

void MBXwrA(void);                 // This function initializes all 32 MBOXes of CAN-A
void MBXwrB(void);                 // This function initializes all 32 MBOXes of CAN-B

/* Create a shadow register structure for the CAN control registers. This is
 needed, since, only 32-bit access is allowed to these registers. 16-bit access
 to these registers could potentially corrupt the register contents. This is
 especially true while writing to a bit (or group of bits) among bits 16 - 31 */

struct ECAN_REGS ECanaShadow;
struct ECAN_REGS ECanbShadow;

main() 
{

/* Kill Watchdog, Init PLL, Enable peripheral clocks */

	InitSysCtrl();
	
/* Initialize the CAN module */

	InitECan();
	InitECanGpio();
    EALLOW;

/* Zero out (or initialize) the entire MBX RAM area */

    MBXwrA();
    MBXwrB();

/* Initialize PIE vector table To a Known State: */
	// The PIE vector table is initialized with pointers to shell "Interrupt 
    // Service Routines (ISR)".  The shell routines are found in DSP28_DefaultIsr.c.
	// Insert user specific ISR code in the appropriate shell ISR routine in 
    // the DSP28_DefaultIsr.c file.
    
    // InitPieVectTable();	 // uncomment this line if the shell ISR routines are needed
    
    // This function is found in DSP28_PieVect.c. It populates the PIE vector table
    // with pointers to the shell ISR functions found in DSP28_DefaultIsr.c. This 
    // function is not useful in this code because the user-specific ISR is present
    // in this file itself. The shell ISR routine in the DSP28_DefaultIsr.c file is
    // not used. If the shell ISR routines are needed, uncomment this line and add 
    // DSP28_PieVect.c & DSP28_DefaultIsr.c files to the project

/* Disable and clear all CPU interrupts: */

	DINT;			// Note that InitPieCtrl() enables interrupts 
	IER = 0x0000;
	IFR = 0x0000;

/* Initialize Pie Control Registers To Default State */
        
	InitPieCtrl(); // This function is found in the DSP28_PieCtrl.c file.        	
	EALLOW;
	DINT;			// Disable interrupts again (for now)
	

/* Write to the MSGID field - MBX number is written as its MSGID */
	
    ECanaMboxes.MBOX1.MSGID.bit.STDMSGID = 1;
    ECanaMboxes.MBOX2.MSGID.bit.STDMSGID = 2;
    ECanaMboxes.MBOX3.MSGID.bit.STDMSGID = 3;
    ECanaMboxes.MBOX4.MSGID.bit.STDMSGID = 4;
    ECanaMboxes.MBOX5.MSGID.bit.STDMSGID = 5;
    ECanaMboxes.MBOX6.MSGID.bit.STDMSGID = 6;
    ECanaMboxes.MBOX7.MSGID.bit.STDMSGID = 7;
    ECanaMboxes.MBOX8.MSGID.bit.STDMSGID = 8;
    ECanaMboxes.MBOX9.MSGID.bit.STDMSGID = 9;
    ECanaMboxes.MBOX10.MSGID.bit.STDMSGID = 10;
    ECanaMboxes.MBOX11.MSGID.bit.STDMSGID = 11;
    ECanaMboxes.MBOX12.MSGID.bit.STDMSGID = 12;
    ECanaMboxes.MBOX13.MSGID.bit.STDMSGID = 13;
    ECanaMboxes.MBOX14.MSGID.bit.STDMSGID = 14;
    ECanaMboxes.MBOX15.MSGID.bit.STDMSGID = 15;
    ECanaMboxes.MBOX16.MSGID.bit.STDMSGID = 16;
    ECanaMboxes.MBOX17.MSGID.bit.STDMSGID = 17;
    ECanaMboxes.MBOX18.MSGID.bit.STDMSGID = 18;
    ECanaMboxes.MBOX19.MSGID.bit.STDMSGID = 19;
    ECanaMboxes.MBOX20.MSGID.bit.STDMSGID = 20;
    ECanaMboxes.MBOX21.MSGID.bit.STDMSGID = 21;
    ECanaMboxes.MBOX22.MSGID.bit.STDMSGID = 22;
    ECanaMboxes.MBOX23.MSGID.bit.STDMSGID = 23;
    ECanaMboxes.MBOX24.MSGID.bit.STDMSGID = 24;
    ECanaMboxes.MBOX25.MSGID.bit.STDMSGID = 25;
    ECanaMboxes.MBOX26.MSGID.bit.STDMSGID = 26;
    ECanaMboxes.MBOX27.MSGID.bit.STDMSGID = 27;
    ECanaMboxes.MBOX28.MSGID.bit.STDMSGID = 28;
    ECanaMboxes.MBOX29.MSGID.bit.STDMSGID = 29;
    ECanaMboxes.MBOX30.MSGID.bit.STDMSGID = 30;
    ECanaMboxes.MBOX31.MSGID.bit.STDMSGID = 31;
    ECanaMboxes.MBOX0.MSGID.bit.STDMSGID = 32;
    
/* Configure CAN-A Mailboxes as Receive mailboxes */

        ECanaShadow.CANMD.all = ECanaRegs.CANMD.all;
        ECanaShadow.CANMD.all = 0xFFFFFFFF;
        ECanaRegs.CANMD.all = ECanaShadow.CANMD.all;

/* Configure CAN-B Mailboxes as Transmit mailboxes */

        ECanbShadow.CANMD.all = ECanbRegs.CANMD.all;
        ECanbShadow.CANMD.all = 0x00000000;
        ECanbRegs.CANMD.all = ECanbShadow.CANMD.all;

/* Enable Mailboxes */

        ECanaShadow.CANME.all = ECanaRegs.CANME.all;
        ECanaShadow.CANME.all = 0xFFFFFFFF;
        ECanaRegs.CANME.all = ECanaShadow.CANME.all;

        ECanbShadow.CANME.all = ECanbRegs.CANME.all;
        ECanbShadow.CANME.all = 0xFFFFFFFF;
        ECanbRegs.CANME.all = ECanbShadow.CANME.all;
		 
	 ECanaRegs.CANMIM.all = 0xFFFFFFFF;	

/* Configure CAN interrupts */ 

	ECanaShadow.CANMIL.all = 0xFFFFFFFF ; // Interrupts asserted on eCAN1INT
	//ECanaShadow.CANMIL.all  = 0x00000000 ; // Interrupts asserted on eCAN0INT	
	ECanaRegs.CANMIL.all = ECanaShadow.CANMIL.all;
	
	ECanaShadow.CANMIM.all  = 0xFFFFFFFF;   // Enable interrupts for all mailboxes
    ECanaRegs.CANMIM.all = ECanaShadow.CANMIM.all;
    
    ECanaShadow.CANGIM.all = 0;	
    // ECanaShadow.CANGIM.bit.I0EN = 1;   // Enable eCAN1INT or eCAN0INT 
    ECanaShadow.CANGIM.bit.I1EN = 1;
    ECanaRegs.CANGIM.all = ECanaShadow.CANGIM.all;
    
/* Reassign ISRs. i.e. reassign the PIE vector for ECAN0INTA_ISR and ECAN0INTA_ISR 
   to point to a different ISR than the shell routine found in DSP28_DefaultIsr.c.
   This is done if the user does not want to use the shell ISR routine but instead
   wants to embed the ISR in this file itself. */
	
	PieVectTable.ECAN0INTA = &eCAN0INT_ISR;
	PieVectTable.ECAN1INTA = &eCAN1INT_ISR;	
    
/* Configure PIE interrupts */    
  
	PieCtrlRegs.PIECTRL.bit.ENPIE = 1;  // Enable vector fetching from PIE block	
	
	PieCtrlRegs.PIEACK.bit.ACK9 = 1;    // Enables PIE to drive a pulse into the CPU

// The interrupt can be asserted in either of the eCAN interrupt lines
// Comment out the unwanted line...

	PieCtrlRegs.PIEIER9.bit.INTx5 = 0;  // Enable INTx.5 of INT9 (eCAN0INT)
	PieCtrlRegs.PIEIER9.bit.INTx6 = 1;  // Enable INTx.6 of INT9 (eCAN1INT)
	
/* Configure system interrupts */
	
	IER |= 0x0100;					// Enable INT9 of CPU
	EINT;
    
/* Begin receiving */

    while(1){}   

}
/* --------------------------------------------------- */
/* ISR for PIE INT9.5  (MBX30)                         */
/* Connected to eCAN0-INTA  eCAN                       */
/* ----------------------------------------------------*/

interrupt void eCAN0INT_ISR(void)  // eCAN
{
   ECanaShadow.CANTA.all = 0 ;
   //ECanaRegs.CANTA.all =  ECanaShadow.CANTA.all ;
   int0count++;
  
   PieCtrlRegs.PIEACK.bit.ACK9 = 1;    // Enables PIE to drive a pulse into the CPU
   IER |= 0x0100;					// Enable INT9 
   EINT;
   return;
}

/* --------------------------------------------------- */
/* ISR for PIE INT9.6 (MBX5)                           */
/* Connected to eCAN1-INTA  eCAN                       */
/* ----------------------------------------------------*/

interrupt void eCAN1INT_ISR(void)  // eCAN
{
   
   asm (" NOP");
   MIV = ECanaRegs.CANGIF1.bit.MIV1; 
   
   switch(MIV)
   {case 1:
   		ECanaShadow.CANRMP.all = 0;
   		ECanaShadow.CANRMP.bit.RMP1 = 1;
   		ECanaRegs.CANRMP.all = ECanaShadow.CANRMP.all ;
   		break;}
         
   int1count++;
   
   PieCtrlRegs.PIEACK.bit.ACK9 = 1;    // Enables PIE to drive a pulse into the CPU
   IER |= 0x0100;					// Enable INT9 
   EINT;
   return;
}

/* Zero-out the MBX RAM of CAN-A */

void MBXwrA()
    {
    int j;
    volatile struct MBOX *Mailbox  = (void *) 0x6100;

        for(j=0; j<32; j++)
        {
            Mailbox->MSGID.all = 0;
            Mailbox->MSGCTRL.all = 0;
            Mailbox->MDH.all = 0;
            Mailbox->MDL.all = 0;
            Mailbox = Mailbox + 1;

        }
    }

/* Initialize the MBX RAM of CAN-B */

void MBXwrB()
    {
    int j;
    volatile struct MBOX *Mailbox  = (void *) 0x6300;

        for(j=0; j<32; j++)
        {
            Mailbox->MSGID.all = 0;
            Mailbox->MSGCTRL.bit.DLC = 8;
            Mailbox->MDH.all = 0x01234567;
            Mailbox->MDL.all = 0X89ABCDEF;
            Mailbox = Mailbox + 1;

        }
    }

/* 

* This example shows how when an interrupt flag is set while another 
* interrupt flag is already set, the most recent interrupt flag automatically
* generates a core level interrupt upon exiting the ISR of the previous interrupt.

* It can be verified that every time a mailbox interrupt is asserted,
* bits[0..4] of the "Global Interrupt Flag" Register contains the 
* mailbox number causing the interrupt. If more interrupt flags are 
* pending, it contains the mailbox number with the highest priority.
* This is done as follows: Disable interrupts and let many mailboxes
* transmit messages. Now enable interrupts. A core level interrupt is
* asserted and upon entering the ISR, examine MIVn bits. It 
* reflects the mailbox number with higher priority.
*/

/*
CAN-B is made to transmit to all the mailboxes using the assigned STD IDs

All 32 mailboxes are allowed to receive and then the interrupts enabled
A counter in the ISR counts the # of times an interrupt was asserted.
This program runs on Node B. CANalyzer is used as node A in this example.
All mailboxes are configured as receive mailboxes. Each mailbox
has a different ID. All mailboxes in node A are allowed to transmit
in a sequence to mailboxes in node B. Once the cycle is complete,
the cycle is started all over again. 

This program loops forever. The # of times the receive loop is executed
is stored in the RXCOUNT value.

The same interupt line (eCANINT0 or eCANINT1) is used.

*/ 

/*  Note: If writing only to the 11-bit identifier as by
    "ECanaMboxes.MBOX1.MSGID.bit.STDMSGID = 1;", IDE, AME & AAM bit fields also
    need to be initialized. Otherwise, they may assume random values. This could
    be done by just initializing the entire register to zero first and then writing
    the STD MSG ID. */
