// 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: RXMSGLST.c                                                
*                                                                    
* Description: This example illustrates the operation OPC bit.
* A mailbox is deliberately allowed to be overwritten and it is checked 
* whether the RMLn and RMLIF bits get set. When the OPC bit is set,
* the message should be stored in the next mailbox with a matching identifier.
* Mailboxes 21 & 20 is used in this 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;
void Config_CAN_B(void);

/* 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();
    
/* 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: */
    EALLOW;
	DINT;
	IER = 0x0000;
	IFR = 0x0000;

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

/* Configure CAN-B to transmit two messages */

	Config_CAN_B();
	
/* Write to the MSGID field  */
    
    ECanaMboxes.MBOX21.MSGID.all = 0x00840000; // Std Identifier (ID = 21)
    ECanaMboxes.MBOX20.MSGID.all = 0x00840000; // Std Identifier (ID = 21)
    
/* Enable Mailboxes under test */
	
	ECanaShadow.CANME.all = ECanaRegs.CANME.all;	
	ECanaShadow.CANME.bit.ME21 = 1;
	ECanaShadow.CANME.bit.ME20 = 1;	 // Enable only for cases 3 & 4
	ECanaRegs.CANME.all = ECanaShadow.CANME.all; 
	
/* Initialize the MBX RAM content to a known value */

	ECanaMboxes.MBOX21.MDH.all = 0;
	ECanaMboxes.MBOX21.MDL.all = 0;
	ECanaMboxes.MBOX20.MDH.all = 0;
	ECanaMboxes.MBOX20.MDL.all = 0;	
	
/* Configure Mailboxes under test as a Receive mailbox */

	ECanaShadow.CANMD.all = ECanaRegs.CANMD.all;	
	ECanaShadow.CANMD.bit.MD21 = 1;
	ECanaShadow.CANMD.bit.MD20 = 1;
	ECanaRegs.CANMD.all = ECanaShadow.CANMD.all; 
	
/* Configure OPCn bit of the mailbox under test (MBX21) */
	
	ECanaShadow.CANOPC.all = ECanaRegs.CANOPC.all;	
	ECanaShadow.CANOPC.bit.OPC21 = 1;	// Set OPC21 = 0 for cases 1 & 3, Set OPC21 = 1 for cases 2 & 4
	ECanaRegs.CANOPC.all = ECanaShadow.CANOPC.all; 
	
/* Configure CAN interrupts */ 

 	ECanaShadow.CANGIM.all = ECanaRegs.CANGIM.all;	
    ECanaShadow.CANGIM.bit.RMLIM = 1;  // Enable "Received message lost" int 
    ECanaShadow.CANGIM.bit.GIL = 0;	   // 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 'Received message lost' 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      
    
/* Begin Receiving */
	
	ECanaRegs.CANRMP.all = 0xFFFFFFFF;	// Clear all RMP bits before receiving
	ECanbRegs.CANTRS.all = 0x00000003;
    
    while(1) {}   // Code just loops here while waiting for data...
}

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

interrupt void eCAN0INT_ISR(void)
{
   ECanaShadow.CANRML.all =  ECanaRegs.CANRML.all ; // Copy RML reg for inspection
   ECanaShadow.CANGIF0.all = ECanaRegs.CANGIF0.all; // Copy GIF0 reg for inspection
   ECanaShadow.CANGIF1.all = ECanaRegs.CANGIF1.all; // Copy GIF1 reg for inspection
   
   asm (" NOP");									 // Useful to set a BP for reg exam

// Clear RML21 (thru RMP21) and hence RMLIF0

	ECanaShadow.CANRMP.all = 0;
	ECanaShadow.CANRMP.bit.RMP21 = 1;
	ECanaRegs.CANRMP.all = ECanaShadow.CANRMP.all;

// Re-enable PIE and Core interrupts   
   PieCtrlRegs.PIEACK.bit.ACK9 = 1;    // Enables PIE to drive a pulse into the CPU
   IER |= 0x0100;					 // Enable INT9 
   EINT;
   int0count++;
   return;
}

/* --------------------------------------------------- */
/* ISR for PIE INT9.6                                  */
/* Connected to HECC1-INTA  eCAN                       */
/* ----------------------------------------------------*/

interrupt void eCAN1INT_ISR(void)
{
   ECanaShadow.CANRML.all =  ECanaRegs.CANRML.all ; // Copy RML reg for inspection
   ECanaShadow.CANGIF0.all = ECanaRegs.CANGIF0.all; // Copy GIF0 reg for inspection
   ECanaShadow.CANGIF1.all = ECanaRegs.CANGIF1.all; // Copy GIF1 reg for inspection
  
   asm (" NOP");									 // Useful to set a Breakpoint for register examination

// Clear RML21 (thru RMP21) and hence RMLIF1

	ECanaShadow.CANRMP.all = 0;
	ECanaShadow.CANRMP.bit.RMP21 = 1;
	ECanaRegs.CANRMP.all = ECanaShadow.CANRMP.all;
	
// Re-enable PIE and Core interrupts   
   PieCtrlRegs.PIEACK.bit.ACK9 = 1;    // Enables PIE to drive a pulse into the CPU
   IER |= 0x0100;					 // Enable INT9 
   EINT;
   int1count++;
   return;
}


void Config_CAN_B()     /* Configure CAN-B to transmit two messages */
{


        /* Write to the MSGID field  */

            ECanbMboxes.MBOX0.MSGID.all = 0x00840000; // Std Identifier (ID = 21)
            ECanbMboxes.MBOX1.MSGID.all = 0x00840000; // Std Identifier (ID = 21)

        /* Enable Mailboxes under test */

            ECanbShadow.CANME.all = ECanbRegs.CANME.all;
            ECanbShadow.CANME.bit.ME0 = 1;
            ECanbShadow.CANME.bit.ME1 = 1;
            ECanbRegs.CANME.all = ECanbShadow.CANME.all;

        /* Initialize the MBX RAM content to a known value */

            ECanbMboxes.MBOX0.MDH.all = 0xAAAAAAAA;
            ECanbMboxes.MBOX0.MDL.all = 0xAAAAAAAA;
            ECanbMboxes.MBOX1.MDH.all = 0xBBBBBBBB;
            ECanbMboxes.MBOX1.MDL.all = 0xBBBBBBBB;

        /* Configure Mailboxes for transmit */

            ECanbShadow.CANMD.all = ECanbRegs.CANMD.all;
            ECanbShadow.CANMD.bit.MD0 = 0;
            ECanbShadow.CANMD.bit.MD1 = 0;
            ECanbRegs.CANMD.all = ECanbShadow.CANMD.all;

         /* Write to DLC field in Master Control reg */

            ECanbMboxes.MBOX0.MSGCTRL.bit.DLC = 8;
            ECanbMboxes.MBOX1.MSGCTRL.bit.DLC = 8;

}
/* 

Note 1: Initialize ECanaShadow.CANRMP.all to zero before setting any bit in order to clear it in the CANRMP register.
Otherwise, some other CANRMP.n bit that is set could be inadvertently cleared

Note 2: If two receive mailboxes have the same ID, the message will be received first
in the mailbox that is numerically higher. (21 in this example)
 
Observations: (Two identical messages are Transmitted from CAN-B)

Case 1: Mailbox 21 alone is enabled. OPC21 = 0
----------------------------------------------
The first message is overwritten by the second message.
RML21 is set and RML interrupt is asserted. RML21, RMP21 and RMLIFn are all
cleared by clearing RMP21. (Not RML21 or RMLIFn).

Case 2: Mailbox 21 alone is enabled. OPC21 = 1
----------------------------------------------
The first message is not overwritten. RML21 is not set. The second
message is lost.

Case 3: Mailboxes 21 & 20 are enabled. OPC21 = 0
------------------------------------------------
The first message is overwritten by the second message in Mailbox 21.
RML21 is set and RML interrupt is asserted RML21, RMP21 and RMLIFn are all
cleared by clearing RMP21. (Not RML21 or RMLIFn).
Mailbox 20 is untouched.

Case 4: Mailboxes 21 & 20 are enabled. OPC21 = 1
------------------------------------------------
The first message is stored in Mailbox 21.
The second message is stored in Mailbox 20.RML21 is not set

All the above 4 cases can be tested using this code by commenting out the
appropriate lines.

*/ 
