CAN-FD support MPC5748G

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

CAN-FD support MPC5748G

Jump to solution
1,816 Views
Kazarian
Contributor III

Hello,

I want to add CAN-FD support to an existing project, the application is a simple Echo, when it receive a CAN message on a Node it will echo it back. the Standard CAN works fine, i modified the init function to support CAN-FD based on project shared by PeterS and updated the register CBT and FDCBT based on this excel sheet.

this is the init function

AbstractCANTransceiver::ErrorCode FlexCANDevice::init()
{
	Io::setDefaultConfiguration(fConfig.txPort);
	Io::setDefaultConfiguration(fConfig.rxPort);
	fPhy.init(fConfig.BusId);

	/* CAN FD init config */
	if(fConfig.fd_enable) 
	{
		/* enable the FlexCAN module, reset and freeze */
		fpDevice->MCR.R = (0
                    | CAN_MCR_FRZ  /* enabled to enter Freeze mode */ 
                    | CAN_MCR_HALT /* enter freeze mode if FRZ bit is set */
                    | CAN_MCR_BCC  /* individual Rx masking and queue */
                    | 0x0000003F); 

		/* double check that we are actually in freeze mode */
		while(0 == fpDevice->MCR.B.FRZACK) {};
		while(0 == fpDevice->MCR.B.NOTRDY) {};    


		fpDevice->MCR.R = (0
                    | CAN_MCR_FRZ  /* enabled to enter Freeze mode */ 
                    | CAN_MCR_HALT /* enter freeze mode if FRZ bit is set */  
                    | CAN_MCR_BCC  /* individual Rx masking and queue */
                    | CAN_MCR_AEN  /* Safe Tx abort enable */
		            | CAN_MCR_FDEN /* CAN FD enabled */
                    | 0x0000003F); /* enable 64 MBs */        
    
		// Set CAN Bit Timing Register (CAN_CBT. P-1747)
		fpDevice->CBT.B.BTF 	 = 1; 	// Enable extended bit time definitions
		fpDevice->CBT.B.EPRESDIV =	fConfig.bitrate_cbt.presDiv;
		fpDevice->CBT.B.ERJW 	 =  fConfig.bitrate_cbt.rjw;  
		fpDevice->CBT.B.EPROPSEG =  fConfig.bitrate_cbt.propSeg;	 
		fpDevice->CBT.B.EPSEG1   =  fConfig.bitrate_cbt.pSeg1;  
		fpDevice->CBT.B.EPSEG2   =  fConfig.bitrate_cbt.pSeg2; 

		// Set CAN FD Bit Timing register (CAN_FDCBT. P-1768)
		fpDevice->FDCBT.B.FPRESDIV = fConfig.bitrate.presDiv;
		fpDevice->FDCBT.B.FRJW     = fConfig.bitrate.rjw;
		fpDevice->FDCBT.B.FPROPSEG = fConfig.bitrate.propSeg;
		fpDevice->FDCBT.B.FPSEG1   = fConfig.bitrate.pSeg1;
		fpDevice->FDCBT.B.FPSEG2   = fConfig.bitrate.pSeg2;
		
		// Set CAN FD Control register (CAN_FDCTRL .P-1766)
		fpDevice->FDCTRL.R = 0;
		fpDevice->FDCTRL.B.FDRATE = 1;   // bit rate switching enable
		fpDevice->FDCTRL.B.MBDSR0 = fConfig.payload;

	}
	/* Standard CAN init config */
	else 
	{
		fpDevice->MCR.B.MDIS = 0; // Enable module

		fpDevice->MCR.R |= MCR_SOFT_RESET_MASK; // Soft reset
		if (isEqualAfterTimeout<vuint32_t>(
					&fpDevice->MCR.R,
					MCR_SOFT_RESET_MASK,
					MCR_SOFT_RESET_MASK,
					INIT_DELAY_TIMEOUT_US))
		{
			return AbstractCANTransceiver::CAN_ERR_INIT_FAILED;
		}

		fpDevice->MCR.B.FRZ = 1; // Enter freeze mode
		fpDevice->MCR.B.HALT = 1;
		if (isEqualAfterTimeout<vuint32_t>(
					&fpDevice->MCR.R,
					MCR_FREEZE_ACK_MASK,
					0UL, INIT_DELAY_TIMEOUT_US))
		{
			return AbstractCANTransceiver::CAN_ERR_INIT_FAILED;
		}

		// Setup MCR
		fpDevice->MCR.B.SRXDIS = 1;   // Disable self reception
		fpDevice->MCR.B.MAXMB = 0x3f; // Use all 64 message buffers
		fpDevice->MCR.B.IRMQ = 1;	  //have to be switch On

		fpDevice->CTRL1.R |= CTRL_TIMING_HIGHSPEED; // 500KB
		
		fpDevice->CTRL2.B.MRP = 1;

	}
	
	// Setup message buffers (Both for Standard CAN and CAN-FD instances)
	fRxInterruptMask = 0;
	uint32_t mask = 1;
	for (uint8_t i = 0; i < fConfig.numRxBufsStd; ++i)
	{
		setupMessageBuffer(i, CANRxBuffer::CODE_EMPTY, false);
		fRxInterruptMask |= mask;
		mask <<= 1;
	}
	mask = (1 << fConfig.numRxBufsStd);
	for (uint8_t i = fConfig.numRxBufsStd;
			i < fConfig.numRxBufsStd + fConfig.numRxBufsExt; ++i)
	{
		setupMessageBuffer(i, CANRxBuffer::CODE_EMPTY, true);
		fRxInterruptMask |= mask;
		mask <<= 1;
	}
	for (uint8_t i = FIRST_TRANSMIT_BUFFER;
			i < FIRST_TRANSMIT_BUFFER + fConfig.numTxBufsApp; ++i)
	{
		setupMessageBuffer(i, CANTxBuffer::CODE_INACTIVE, false);
	}
	setupMessageBuffer(CALLBACK_TRANSMIT_BUFFER, CANTxBuffer::CODE_INACTIVE, false);

	// Clear and disable interrupts
	fpDevice->RXMGMASK.R = 0;
	fpDevice->RX14MASK.R = 0;
	fpDevice->RX15MASK.R = 0;

	fpDevice->IMASK1.R = 0;
	fpDevice->IMASK2.R = 0;

	fpDevice->IFLAG1.R = 0xffffffff;
	fpDevice->IFLAG2.R = 0xffffffff;
	fpDevice->ESR1.R = 0xffffffff;
	fFirstRxId = 0;
	fFramesReceived = 0;

	return AbstractCANTransceiver::CAN_ERR_OK;
}

void setupMessageBuffer(uint8_t bufIdx, uint8_t code, bool extended)
{
	fpDevice->MB[bufIdx].CS.R = 0;
	fpDevice->MB[bufIdx].CS.B.IDE = extended ? 1 : 0;
	fpDevice->MB[bufIdx].CS.B.CODE = code;
	fpDevice->MB[bufIdx].ID.R = 0;
	fpDevice->MB[bufIdx].DATA.W[0] = 0;
	fpDevice->MB[bufIdx].DATA.W[1] = 0;
	fpDevice->RXIMR[bufIdx].R = 0;
}

namespace CANRxBuffer
{
	enum Code
	{
		CODE_INACTIVE 	= 0,
		CODE_FULL 		= 2,
		CODE_EMPTY 		= 4,
		CODE_OVERRUN 	= 5
	};
	static const uint32_t FLAG_BUSY = (1UL << 24);
}

 

The receive interrupt handler

uint8_t FlexCANDevice::receiveISR(const uint8_t* filterMap)
{
	if(fConfig.fd_enable) 
	{
		TransmitMsgFD(0,0x155,8);
	}
	else
	{
		TransmitMsgSTD(0,0x155,8);
	}
}

 

and the CAN node configuration 

const ::bios::FlexCANDevice::Config Can1Config =
{
	(0xFBEC0000UL),
	::can::AbstractCANTransceiver::BAUDRATE_HIGHSPEED,
	::bios::Io::canGS1Tx,
	::bios::Io::canGS1Rx,
	NUM_RX_STD_MAILBOXES,
	NUM_RX_EXT_MAILBOXES,
	NUM_TX_MAILBOXES,
	::cgw3::busid::BusId::KCAN(),	//busid
	::bios::EdgeWakeUp::KWUP_5,		//wakeUp
	true,							// CAN-FD enabled
	::can::AbstractCANTransceiver::FLEXCAN_PAYLOAD_SIZE_8, 
	// for exact configuration refer to xls file ..\tools\CAN Bit Timing calculation v2.1
	// Arbitration phase, CANx_CBT = 0x80242AC4;  bitrate=500kbps, CPI clk=40 MHz; Prescaler= 2, PROPSEG=11, PSEG1=23, PSEG2=5, RJW=5, smp=87,5%
	{
		1, 			/*!< Prescaler Division Factor*/
		4, 			/*!< Resync Jump Width*/
		10, 			/*!< Propagation Segment*/
		22, 			/*!< Phase Segment 1*/
		4			/*!< Phase Segment 2*/
	},
	// Data Phase, CANx_FDCBT = 0x00111421;  // bitrateFD=2000kbps, CPI clk=40 MHz; fPrescaler= 2, fPROPSEG=5, fPSEG1=2, fPSEG2=2, fRJW=2, smp=80%
	{
		1, 			/*!< Prescaler Division Factor*/
		1, 			/*!< Resync Jump Width*/
		5, 			/*!< Propagation Segment*/
		1, 			/*!< Phase Segment 1*/
		1			/*!< Phase Segment 2*/
	},
};

  when i switch to CAN-FD  the receive interrupt never happen. probably something wrong with the init or buffer config ? 

Thanks a lot.

0 Kudos
Reply
1 Solution
1,791 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi,

I see you have CTRL2[ISOCANFDEN] cleared, so FlexCAN operates using the non-ISO CAN FD protocol. Be sure your Vector tool is using same one.
I think setting ISOCANFDEN would help.

BR, Petr

View solution in original post

14 Replies
1,798 Views
Kazarian
Contributor III

@PetrS Thanks a lot for your answer.

here is the register setup after initialisation :

Kazarian_0-1709824761467.png

Complete register view :

Kazarian_1-1709824797843.pngKazarian_2-1709824831503.png

The message buffer :

Kazarian_3-1709824857193.png

we use Vector cancase to send CAN-FD fram, based on the input from the excel sheet, i choose to set the following  

            // arbitration bitrate
            canFdConf.arbitrationBitRate = 500000;
            canFdConf.tseg1Abr = 34;
            canFdConf.tseg2Abr = 5;
            canFdConf.sjwAbr = 4;

            // data bitrate
            canFdConf.dataBitRate = canFdConf.arbitrationBitRate * 4;
            canFdConf.tseg1Dbr = 31;
            canFdConf.tseg2Dbr = 8;
            canFdConf.sjwDbr = 1;

ESR1 suggest that an ovverus is occured, and the FlexCAN is not synchronised with the bus, where did the problem comes from ?

ECR has a value of 0x40005E00

Thank you

0 Kudos
Reply
1,792 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi,

I see you have CTRL2[ISOCANFDEN] cleared, so FlexCAN operates using the non-ISO CAN FD protocol. Be sure your Vector tool is using same one.
I think setting ISOCANFDEN would help.

BR, Petr

1,746 Views
Kazarian
Contributor III

@PetrS  Thank you, this was the problem.

Interrupt is activated for the receive function, and disable for the transmission. 

i can receive CAN-FD frames via ISR. but when i want to send them the program get stucked in function TransmitMsgFD ,  in line : while (fpDevice->IFLAG1.B.BUF0I != 1) {};:

 

void FlexCANDevice::TransmitMsgFD(uint8_t ext, uint32_t ID, uint8_t length, uint8_t* data)
{
	uint8_t	i,dlc,z=0;               
	uint32_t *pTxMB = (uint32_t *)&(fpDevice->MB[0].CS.R);
	uint32_t txID;

	if (ext==0) txID = ID<<18;
	else txID = ID;

	/*calculate dlc value from no. bytes*/
	dlc = length < 0x09 ? length : 
		  length < 0x0D ? 0x9 : 
		  length < 0x11 ? 0xA : 
		  length < 0x15 ? 0xB : 
		  length < 0x19 ? 0xC : 
		  length < 0x21 ? 0xD : 
		  length < 0x31 ? 0xE : 0xF;

	

	*(pTxMB + 1) = txID;	// write ID

	for (i=0; i<length/4; i++,z+=4) {
		*(pTxMB + 2 + i) =  z<<24 | (z+1)<<16 | (z+2)<< 8 | z+3;      /* Data to be transmitted */
	}

	*pTxMB = ( 0	// Tx Buffer 0 T0 word
			| 1<<31	// extended Data Length
			| 1<<30	// bit rate switch
			| 0xC<<24	// code = 0xC, TX once
			| 1<<22	// SRR = 1
			| ext<<21	// IDE 
			| 0<<20	// RTR = 0
			| dlc<<16);  // DLC 

	while (fpDevice->IFLAG1.B.BUF0I != 1) {};  /***** Program get stuck here *******/
	fpDevice->IFLAG1.R = 1;	// clear MB0 flag

}

 

CAN1 is set to send and receive data, the MB0 for sending, and MB1 for receiving. from the debuger view i can see that data are available in MB0 but i dont understand why they were not processed

Kazarian_0-1710240789903.png

any though why this could happen ?

Thank you.

 

 

0 Kudos
Reply
1,743 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi,

seems message is not transmitted successfully without error, so flag is no set. Check bus lines and ECR/ESR1 registers.

BR, Petr

0 Kudos
Reply
1,738 Views
Kazarian
Contributor III

Content of ECR and ESR1 registers are :

Please note that transmission is done via a task and not an interrupt (queued and later processed).

reception in the other hand is handled via an ISR. 

Kazarian_0-1710242771729.png

Thank you !

0 Kudos
Reply
1,731 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi,

mode of flag handling does not matter here. You got bit error and it is going to bus off, recover and again the same. Could be due to transceiver issue, wrong bit timing used, TDC setting if used. Check that.
You can try sending without BRS set.

BR, Petr

0 Kudos
Reply
1,704 Views
Kazarian
Contributor III

Thanks a lot @PetrS for your support.

By disabling the BSR i could receive data.

There is a problem though. the application should only Echo "once" the same received frame, but it keep transmiting frames without stop , event though i make sure to clear the receive interrupt once the transmission is completed (fpDevice->IFLAG1.R = 0xffffffff;) .

Kazarian_0-1710323880654.png

uint8_t start()
{
	// Clear interrupt flags
	fpDevice->IFLAG1.R = 0xffffffff;
	fpDevice->IFLAG2.R = 0xffffffff;

	// Disable transmit interrupt on MB0
	fpDevice->IMASK2.B.BUFHM = 0;  // Disable transmit interrupt on MB0

	// Enable receive interrupt on MB1
	fpDevice->IMASK1.B.BUFLM |= 0x00000002;  // Enable receive interrupt on MB1
	
	// Leave freeze mode
	fpDevice->MCR.B.HALT = 0;
	fpDevice->MCR.B.FRZ = 0;

	return CAN_ERR_OK;
}

uint8_t receiveISR(const uint8_t* filterMap)
{
		
	uint32_t  dummy,dlc,id;
	uint8_t   *pRxMB;
	uint32_t  RxCODE;              /* Received message buffer code */
	uint32_t  RxID;                /* Received message ID */
	uint32_t  RxLENGTH;            /* Recieved message number of data bytes */
	uint8_t   RxDATA[64];          /* Received message data string*/
	uint32_t  RxTIMESTAMP;         /* Received message time */

	bufIdx = 1;  				   /* MB1 for receiving frames */
	
	/* Read CODE, ID, LENGTH, DATA, TIMESTAMP*/	
	id 		 = fpDevice->MB[bufIdx].CS.B.IDE;
	RxCODE   = fpDevice->MB[bufIdx].CS.B.CODE; 
	RxID     = fpDevice->MB[bufIdx].ID.B.ID_STD;
	dlc 	 = fpDevice->MB[bufIdx].CS.B.DLC;
	pRxMB    = (uint8_t *)&fpDevice->MB[bufIdx].DATA.B[0];
	RxTIMESTAMP = fpDevice->MB[bufIdx].CS.B.TIMESTAMP; 
	
	/*calculate no. bytes from dlc value*/
	RxLENGTH = (dlc <=  ? dlc : (dlc == 0x9 ? 12 : (dlc == 0xA ? 16 : (dlc == 0xB ? 20 : (dlc == 0xC ? 24 : (dlc == 0xD ? 32 : (dlc == 0xE ? 48 : 64))))));
	
	for (uint8_t j=0; j<RxLENGTH; j++) { 
		RxDATA[j] = *pRxMB++ ;
	}
	
	// Echo back the Received message
	TransmitMsgFD(id, RxID, RxLENGTH,  RxDATA);  
	
	// Unlock and clear buffer
	dummy = fpDevice->TIMER.R;             /* Read TIMER to unlock message buffers */   
	fpDevice->IFLAG1.R = 0xffffffff;       /* Clear MB 1 flag */ 			
	return 0;
		
}

void TransmitMsgFD(uint8_t ext, uint32_t ID, uint8_t length, uint8_t* data)
{
	uint8_t	i,dlc,tx_BuffIdx = 0;   /* MB0 for sending frames */             
	uint32_t *pTxMB = (uint32_t *)&(fpDevice->MB[tx_BuffIdx].CS.R);
	uint32_t txID;

	if (ext==0) txID = ID<<18;
	else txID = ID;

	/*calculate dlc value from no. bytes*/
	dlc = length < 0x09 ? length :  length < 0x0D ? 0x9 :  length < 0x11 ? 0xA :  length < 0x15 ? 0xB :  length < 0x19 ? 0xC : length < 0x21 ? 0xD :   length < 0x31 ? 0xE : 0xF;

	
	// write ID
	*(pTxMB + 1) = txID;	

	/* Data to be transmitted */
	for (i = 0; i < length / 4; i++) {
		*(pTxMB + 2 + i) = data[i*4] << 24 | data[i*4 + 1] << 16 | data[i*4 + 2] << 8 | data[i*4 + 3];
	}


	*pTxMB = ( tx_BuffIdx	// Tx Buffer 0 T0 word
			| 1<<31	// extended Data Length
			//| 1<<30	// bit rate switch
			| 0xC<<24	// code = 0xC, TX once
			| 1<<22	// SRR = 1
			| ext<<21	// IDE 
			| 0<<20	// RTR = 0
			| dlc<<16);  // DLC 

	while (fpDevice->IFLAG1.B.BUF0I != 1) {};  
	fpDevice->IFLAG1.R = 1;	// clear MB0 flag
}

Any though why this is happening ? 

Best regards.

0 Kudos
Reply
1,698 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi,

disable self reception MCR[SRXDIS]=1. If you have enabled it still and sending ID matches received one, it will go to RX ISR again and again. 

And do not use fpDevice->IFLAG1.R = 0xffffffff for clearing single MB flag. Write just the one you want to clear.

BR, Petr

1,695 Views
Kazarian
Contributor III

Thanks a lot @PetrS this works for me now

i will try to setup the register to support data up to 64 bytes. 

Best regards.

0 Kudos
Reply
1,806 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi,

from a code it is hard to imagine actual configuration, so it would be better to see register and MB content after init and after message was received.
I can just point to check MB offset if payload other than 8bytes is used. Then of course check if any error is detected (ECR/ESR1) register. Only error free transmission/reception set MB flag, thus interrupt can be generated if enabled on FlexCAN and core.

BR, Petr

0 Kudos
Reply
1,495 Views
xiha
Contributor II

I want to use 14 MBs of payload=64, if i use 7->13 MBs , i can't send  successfully.My key configuration is as follows:

CAN_0.MCR --->   MAXMB= 0x0000000D; //14 MBS,  0xD+1

CAN_0.FDCTRL ----> MBDSR1 = 11,  MBDSR0 = 11

Are there any additional places that need to be configured???

 

 

0 Kudos
Reply
1,486 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi,

as I wrote, be sure right MB offset is used.

BR, Petr

0 Kudos
Reply
1,426 Views
xiha
Contributor II

Ok,I will check it.Thanks for you,Best PetrS

0 Kudos
Reply
1,424 Views
xiha
Contributor II

It's off by 8 bytes.

  • MB7-MB6 = 80
  • MB6-MB5 = 72,

That's why i failed.

0 Kudos
Reply