// 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: MULTINT2.c                                               *
*                                                                    *
* Description: Illustrates the ability of the CAN module to service 
* multiple interrupts  automatically. 

All 32 mailboxes are allowed to transmit and then the interrupts enabled
A counter in the ISR counts the # of times an interrupt was asserted.

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

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

//
// 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

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

/* 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;

main() 
{

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

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

	InitECan(); 
	InitECanGpio();
    EALLOW;

/* 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 of TRANSMIT mailboxes MBOX0 - 31 */
    
    ECanaMboxes.MBOX0.MSGID.all = 0x9555AAA0; 
    ECanaMboxes.MBOX1.MSGID.all = 0x9555AAA1; 
    ECanaMboxes.MBOX2.MSGID.all = 0x9555AAA2; 
    ECanaMboxes.MBOX3.MSGID.all = 0x9555AAA3; 
    ECanaMboxes.MBOX4.MSGID.all = 0x9555AAA4; 
    ECanaMboxes.MBOX5.MSGID.all = 0x9555AAA5; 
    ECanaMboxes.MBOX6.MSGID.all = 0x9555AAA6; 
    ECanaMboxes.MBOX7.MSGID.all = 0x9555AAA7; 
    ECanaMboxes.MBOX8.MSGID.all = 0x9555AAA8; 
    ECanaMboxes.MBOX9.MSGID.all = 0x9555AAA9; 
    ECanaMboxes.MBOX10.MSGID.all = 0x9555AA10; 
    ECanaMboxes.MBOX11.MSGID.all = 0x9555AA11; 
    ECanaMboxes.MBOX12.MSGID.all = 0x9555AA12; 
    ECanaMboxes.MBOX13.MSGID.all = 0x9555AA13; 
    ECanaMboxes.MBOX14.MSGID.all = 0x9555AA14; 
    ECanaMboxes.MBOX15.MSGID.all = 0x9555AA15; 
    
    ECanaMboxes.MBOX16.MSGID.all = 0x9555AA16; 
    ECanaMboxes.MBOX17.MSGID.all = 0x9555AA17; 
    ECanaMboxes.MBOX18.MSGID.all = 0x9555AA18; 
    ECanaMboxes.MBOX19.MSGID.all = 0x9555AA19; 
    ECanaMboxes.MBOX20.MSGID.all = 0x9555AA20; 
    ECanaMboxes.MBOX21.MSGID.all = 0x9555AA21; 
    ECanaMboxes.MBOX22.MSGID.all = 0x9555AA22; 
    ECanaMboxes.MBOX23.MSGID.all = 0x9555AA23; 
    ECanaMboxes.MBOX24.MSGID.all = 0x9555AA24; 
    ECanaMboxes.MBOX25.MSGID.all = 0x9555AA25; 
    ECanaMboxes.MBOX26.MSGID.all = 0x9555AA26; 
    ECanaMboxes.MBOX27.MSGID.all = 0x9555AA27; 
    ECanaMboxes.MBOX28.MSGID.all = 0x9555AA28; 
    ECanaMboxes.MBOX29.MSGID.all = 0x9555AA29; 
    ECanaMboxes.MBOX30.MSGID.all = 0x9555AA30; 
    ECanaMboxes.MBOX31.MSGID.all = 0x9555AA31; 
 
 /* Configure Mailboxes 0-31 as Tx */

	ECanaRegs.CANMD.all = 0x00000000; 
	
/* Enable all Mailboxes */
	
	ECanaRegs.CANME.all = 0xFFFFFFFF;
	
/* Write to Master Control field - DLC */
 
    ECanaMboxes.MBOX0.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX1.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX2.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX3.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX4.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX5.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX6.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX7.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX8.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX9.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX10.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX11.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX12.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX13.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX14.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX15.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX16.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX17.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX18.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX19.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX20.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX21.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX22.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX23.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX24.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX25.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX26.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX27.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX28.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX29.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX30.MSGCTRL.bit.DLC = 8;
    ECanaMboxes.MBOX31.MSGCTRL.bit.DLC = 8;
 
/* Write to the mailbox RAM field of MBOX0 - 31 */
    
     ECanaMboxes.MBOX0.MDL.all = 0x9555AAA0;
	 ECanaMboxes.MBOX0.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX1.MDL.all = 0x9555AAA1;
	 ECanaMboxes.MBOX1.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX2.MDL.all = 0x9555AAA2;
	 ECanaMboxes.MBOX2.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX3.MDL.all = 0x9555AAA3;
	 ECanaMboxes.MBOX3.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX4.MDL.all = 0x9555AAA4;
	 ECanaMboxes.MBOX4.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX5.MDL.all = 0x9555AAA5;
	 ECanaMboxes.MBOX5.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX6.MDL.all = 0x9555AAA6;
	 ECanaMboxes.MBOX6.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX7.MDL.all = 0x9555AAA7;
	 ECanaMboxes.MBOX7.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX8.MDL.all = 0x9555AAA8;
	 ECanaMboxes.MBOX8.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX9.MDL.all = 0x9555AAA9;
	 ECanaMboxes.MBOX9.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX10.MDL.all = 0x9555AAAA;
	 ECanaMboxes.MBOX10.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX11.MDL.all = 0x9555AAAB;
	 ECanaMboxes.MBOX11.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX12.MDL.all = 0x9555AAAC;
	 ECanaMboxes.MBOX12.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX13.MDL.all = 0x9555AAAD;
	 ECanaMboxes.MBOX13.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX14.MDL.all = 0x9555AAAE;
	 ECanaMboxes.MBOX14.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX15.MDL.all = 0x9555AAAF;
	 ECanaMboxes.MBOX15.MDH.all = 0x89ABCDEF;	 
	 
	 ECanaMboxes.MBOX16.MDL.all = 0x9555AA10;
	 ECanaMboxes.MBOX16.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX17.MDL.all = 0x9555AA11;
	 ECanaMboxes.MBOX17.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX18.MDL.all = 0x9555AA12;
	 ECanaMboxes.MBOX18.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX19.MDL.all = 0x9555AA13;
	 ECanaMboxes.MBOX19.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX20.MDL.all = 0x9555AA14;
	 ECanaMboxes.MBOX20.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX21.MDL.all = 0x9555AA15;
	 ECanaMboxes.MBOX21.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX22.MDL.all = 0x9555AA16;
	 ECanaMboxes.MBOX22.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX23.MDL.all = 0x9555AA17;
	 ECanaMboxes.MBOX23.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX24.MDL.all = 0x9555AA18;
	 ECanaMboxes.MBOX24.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX25.MDL.all = 0x9555AA19;
	 ECanaMboxes.MBOX25.MDH.all = 0x89ABCDEF;	 
	 
	 ECanaMboxes.MBOX26.MDL.all = 0x9555AA1A;
	 ECanaMboxes.MBOX26.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX27.MDL.all = 0x9555AA1B;
	 ECanaMboxes.MBOX27.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX28.MDL.all = 0x9555AA1C;
	 ECanaMboxes.MBOX28.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX29.MDL.all = 0x9555AA1D;
	 ECanaMboxes.MBOX29.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX30.MDL.all = 0x9555AA1E;
	 ECanaMboxes.MBOX30.MDH.all = 0x89ABCDEF;
	 
	 ECanaMboxes.MBOX31.MDL.all = 0x9555AA1F;
	 ECanaMboxes.MBOX31.MDH.all = 0x89ABCDEF;
		 
	 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
    
/* Begin transmitting */

	 ECanaRegs.CANTA.all = 0xFFFFFFFF;  // Clear all "set" TAn bits, if any
     ECanaRegs.CANTRS.all = 0xFFFFFFFF; // Set TRS for all mailboxes                                       
     
     while(ECanaRegs.CANTA.all != 0xFFFFFFFF) {}
      
     EINT;							   // Global enable of interrupts 
     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 31:
   		ECanaShadow.CANTA.all = 0;
   		ECanaShadow.CANTA.bit.TA31 = 1;
   		ECanaRegs.CANTA.all = ECanaShadow.CANTA.all ;
   		break;
   		
   	case 30:
   		ECanaShadow.CANTA.all = 0;
   		ECanaShadow.CANTA.bit.TA30 = 1;
   		ECanaRegs.CANTA.all = ECanaShadow.CANTA.all ;
   		break;	
   		
   	case 29:
   		ECanaShadow.CANTA.all = 0;
   		ECanaShadow.CANTA.bit.TA29 = 1;
   		ECanaRegs.CANTA.all = ECanaShadow.CANTA.all ;
   		break;	
   		
   	case 28:
   		ECanaShadow.CANTA.all = 0;
   		ECanaShadow.CANTA.bit.TA28 = 1;
   		ECanaRegs.CANTA.all = ECanaShadow.CANTA.all ;
   		break;		
   	
   	case 27:
   		ECanaShadow.CANTA.all = 0;
   		ECanaShadow.CANTA.bit.TA27 = 1;
   		ECanaRegs.CANTA.all = ECanaShadow.CANTA.all ;
   		break;		
   	
   	case 26:
   		ECanaShadow.CANTA.all = 0;
   		ECanaShadow.CANTA.bit.TA26 = 1;
   		ECanaRegs.CANTA.all = ECanaShadow.CANTA.all ;
   		break;		
   	}
   // ECanaShadow.CANTA.all = ECanaRegs.CANTA.all ;
      
   int1count++;
   
   PieCtrlRegs.PIEACK.bit.ACK9 = 1;    // Enables PIE to drive a pulse into the CPU
   IER |= 0x0100;					// Enable INT9 
   EINT;
   return;
}

/* 

* 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.

Case 2: All 32 mailboxes are allowed to transmit. It is then checked 
whether interrupts were asserted 32 times.

(Only 7 mailboxes are checked and hence interrupt is asserted 7 times )

* 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.
*/


    
