// 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: MBXWDIF.c                                                
*                                
* Description: This code illustrates the functionality of the WDIFn bit.
* (WDIF- Write Denied Interrupt Flag)
* The identifier field of a mailbox is written to, while it is enabled.
* This would set WDIFn bit and assert a CAN interrupt.
* MBX13 is used as an example.
*
*********************************************************************/

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

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

//void InitECan(void);

main() 

{

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

        InitSysCtrl();

    /* Initialize the CAN module */

        InitECana();
        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;
	IER = 0x0000;
	IFR = 0x0000;

/* Initialize Pie Control Registers To Default State */
        
	InitPieCtrl(); // This function is found in the DSP28_PieCtrl.c file.        	

/* Write the MSGID prior to enabling (Not strictly required as part of test) */ 
    
    ECanaMboxes.MBOX13.MSGID.all  = 0x9555AA13;   
       
/* Write to the mailbox RAM field (Not strictly required as part of test) */ 
    
     ECanaMboxes.MBOX13.MDL.all = 0x31313131;
	 ECanaMboxes.MBOX13.MDH.all = 0x13131313; 
	     
/* Enable Mailbox(es) under test */ 
	
	ECanaShadow.CANME.all = ECanaRegs.CANME.all;
	ECanaShadow.CANME.bit.ME13 = 1;
	ECanaRegs.CANME.all = ECanaShadow.CANME.all;
		 
/* Configure CAN interrupts */ 
	
 	ECanaShadow.CANGIM.all = ECanaRegs.CANGIM.all;	
    ECanaShadow.CANGIM.bit.WDIM = 1;   // Enable "Write denied" int 
    ECanaShadow.CANGIM.bit.GIL = 1;	   // GIL value determines eCAN(0/1)INT
    								   // Enable the int line chosen by GIL
    //ECanaShadow.CANGIM.bit.I0EN = 1;   // Uncomment this line if GIL = 0   
    ECanaShadow.CANGIM.bit.I1EN = 1;   // Uncomment this line if GIL = 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 'Write-denied' interrupt can be asserted in either of the eCAN interrupt lines
// Comment out the unwanted line...

	PieCtrlRegs.PIEIER9.bit.INTx5 = 1;  // 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;							// Global enable of interrupts       
   
/* Now attempt to write to the MSGID field of the mailboxes */

    ECanaMboxes.MBOX13.MSGID.all  = 0x9555AA00;  
    asm(" NOP");		// Atleast 8 NOPs are needed  
    asm(" NOP"); 		// in order for the second write
    asm(" NOP");		// to assert another interrupt.
    asm(" NOP");		// Otherwise, the second write
    asm(" NOP");        // would try  to set the "already set"
    asm(" NOP");        // WDIF, thereby failing to assert the
    asm(" NOP");		// second interrupt.
    asm(" NOP");    
    ECanaMboxes.MBOX13.MSGID.all  = 0x9555AA00;     									  
    
    while(1) {} 
     
}

/* --------------------------------------------------- */
/* ISR for PIE INT9.5                          */
/* Connected to HECC0-INTA  eCAN                       */
/* ----------------------------------------------------*/

interrupt void eCAN0INT_ISR(void)  // eCAN
{
   // Clear WDIFO flag bit..
   ECanaShadow.CANGIF0.all = ECanaRegs.CANGIF0.all;
   ECanaShadow.CANGIF0.bit.WDIF0 = 1;
   ECanaRegs.CANGIF0.all = ECanaShadow.CANGIF0.all;
   int0count++;						// Interrupt counter
   
   // Re-enable core interrupts and CAN int from PIE module
   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                           */
/* Connected to HECC1-INTA  eCAN                       */
/* ----------------------------------------------------*/

interrupt void eCAN1INT_ISR(void)  // eCAN
{
   
   // Clear WDIF1 flag bit..
   ECanaShadow.CANGIF1.all = ECanaRegs.CANGIF1.all;
   ECanaShadow.CANGIF1.bit.WDIF1 = 1;
   ECanaRegs.CANGIF1.all = ECanaShadow.CANGIF1.all;
   int1count++;						// Interrupt counter
   
   // Re-enable core interrupts and CAN int from PIE module
   PieCtrlRegs.PIEACK.bit.ACK9 = 1;    // Enables PIE to drive a pulse into the CPU
   IER |= 0x0100;					 // Enable INT9 
   EINT;
   return;
}

/* When a maskable interrupt request is sent to the CPU the following basic steps
 are taken by the device:
 
1. Set the proper IFR bit
2. Check if interrupt enabled (Is proper IER bit set?)
3. Check if global interrupts enabled (Is INTM cleared?)
If both 2 and 3 are true, then proceed as follows:
4. Clear IFR
5. Store PC, fetch vector, adjust stack, perform context save
6. Clear corresponding IER bit   (note this register was part of the context save
   before the bit was cleared)
7. Set INTM (mask global interrupts)  [note this bit is in ST1 which was part of 
   the context save before it was set]
8. Execute interrupt service routine
9. Perform context restore (also restores IER and INTM)
10.Continue program execution
 
By the time we get to the ISR routine, masked interrupts are disabled (INTM is set)
and interrupts from the same vector are also disabled.  In this way, no maskable
interrupts will be serviced while we are in the ISR unless we choose to enable them.
 
In this example ISR, the following instructions would be used if nested interrupts are
to be allowed: 

   IER |= 0x0100;                      // Enable INT9
   EINT;

What one might choose to do is only accept interrupts from a different
INT line - so the IER instruction might not be enabling the current interrupt, but instead
allow a different interrupt to come through.  Basically in this manner one can do software
prioritization by allowing some interrupts to be interrupted themselves. 

The PIEACK instruction:
 
   PieCtrlRegs.PIEACK.bit.ACK9 = 1;    // Enables PIE to drive a pulse into the CPU

tells the PIE that you are going to allow interrupts from that group to go on to the CPU
(assuming the proper PIER register bit is set).  This instruction should be placed in the
routine where you want this to allow this - it might be at the beginning or at the end
as the last thing you do before you exit.   If you do not do this you will never receive
another interrupt from that group. 

*/

