CAN-FD support MPC5748G

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 
已解决

CAN-FD support MPC5748G

跳至解决方案
1,813 次查看
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 项奖励
回复
1 解答
1,788 次查看
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

在原帖中查看解决方案

14 回复数
1,795 次查看
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 项奖励
回复
1,789 次查看
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,743 次查看
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 项奖励
回复
1,740 次查看
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 项奖励
回复
1,735 次查看
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 项奖励
回复
1,728 次查看
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 项奖励
回复
1,701 次查看
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 项奖励
回复
1,695 次查看
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,692 次查看
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 项奖励
回复
1,803 次查看
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 项奖励
回复
1,492 次查看
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 项奖励
回复
1,483 次查看
PetrS
NXP TechSupport
NXP TechSupport

Hi,

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

BR, Petr

0 项奖励
回复
1,423 次查看
xiha
Contributor II

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

0 项奖励
回复
1,421 次查看
xiha
Contributor II

It's off by 8 bytes.

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

That's why i failed.

0 项奖励
回复