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.
Solved! Go to Solution.
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
@PetrS Thanks a lot for your answer.
here is the register setup after initialisation :
Complete register view :
The message buffer :
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
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
@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
any though why this could happen ?
Thank you.
Hi,
seems message is not transmitted successfully without error, so flag is no set. Check bus lines and ECR/ESR1 registers.
BR, Petr
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.
Thank you !
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
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;) .
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.
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
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.
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
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???
Hi,
as I wrote, be sure right MB offset is used.
BR, Petr
Ok,I will check it.Thanks for you,Best PetrS
It's off by 8 bytes.
That's why i failed.