Hi there,
I am having a bit of trouble with the MSCAN module in the 56F8037. In particular, I am currently trying to get it to transmit data.
I have this sort of working, in that I can transmit data ok at various speeds and recieve it on my PC but I am having trouble with sending more than 3 lots of data and I think it is related to the transmit buffers.
For example, I have set up my controller to just send some static data over the CAN module to test if it was working. This was something like: (I populated all bytes in between - they are just omitted for clarity)
outData[0] = 11; to outData[7] = 18; // Populate tx data
can_Send_Pkt(outData, toID, fromID); // Send it off
outData[0] = 21; to outData[7] = 28;
can_Send_Pkt(outData, toID, fromID);
outData[0] = 31; to outData[7] = 38;
can_Send_Pkt(outData, toID, fromID);
outData[0] = 41; to outData[7] = 48;
can_Send_Pkt(outData, toID, fromID);
And so on, up to 71,...,78.
All I recieve on the other end of the CAN bus is the data from
11,...,18
21,...,28
31,...,38
And it will just keep repeating this. (ie 11, 12, 13, 14, 16, 17, 18)
It seems as though I can write to the tx data buffer once, then that is all. The datasheet says that the only way to clear out a tx data buffer is by writing to it. I do think something is screwy in the way I am putting data into the tx Buffers and I also think my selection of TX buffer is a bit suspect, but I cannot put my finger on it.
I wonder if anyone could take a quick look at my code below and see if they can see something I cannot.
The code is based on the Quickstart example and some other stuff I lifted from the depths of the Codewarrior directory.
I have included 2 versions of my testing code below. The top one gives the above results. The bottom one just transmits one register. I believe the bottom one is a step in the right direction.
1st try:
// ------------------------------------------------ CAN - TX READY ISR -----------------------------------
#pragma interrupt on
void CAN_TxRdy_ISR(void)
{
// what tx buffers are empty?
UWord16 tint = ioctl(MSCAN, MSCAN_READ_TINT_FLAGS, NULL); // AVailable buffers
// disable interrupts handled
ioctl(MSCAN, MSCAN_TINT_DISABLE, tint);
}
#pragma interrupt off
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
static void send_CAN_Pkt(UWord16 outMode, UWord16 txCmd, UWord16 outID, UWord16* sndData) {
static UWord32 outIdCAN;
static UWord16 txbuff;
// Select the next available TX buffer
txbuff = ioctl(MSCAN, MSCAN_SELECT_NEXT_TXBUFF, NULL);
if(txbuff) {
// Pointer to TX buffer
register UWord16* pdT = ioctl(MSCAN_TB, MSCANMB_GET_DATAPTR, NULL);
pdT[0] = sndData[0];
pdT[1] = sndData[1];
pdT[2] = sndData[2];
pdT[3] = sndData[3];
pdT[4] = sndData[4];
pdT[5] = sndData[5];
pdT[6] = sndData[6];
pdT[7] = sndData[7];
outID = ((ecID << 4) & FROM_MASK) | (outMode << 8); // (1 << 8) is the Mode part. Change to (Mode << 8)
ioctl(MSCAN_TB, MSCANMB_SET_ID, outID);
ioctl(MSCAN_TB, MSCANMB_SET_LEN, 8);
// transmit buffer
ioctl(MSCAN, MSCAN_TRANSMIT, txbuff);
// enable tx-finished interrupt
ioctl(MSCAN, MSCAN_TINT_ENABLE, txbuff);
}
}
-------------------------
2nd try
// ------------------------------------------------ CAN - TX READY ISR -----------------------------------
#pragma interrupt on
void CAN_TxRdy_ISR(void)
{
register UWord16 txbNum;
register UWord16 bflag;
UWord16 tEmpty = ioctl(MSCAN, MSCAN_READ_TINT_FLAGS, NULL); // AVailable buffers
for (txbNum=0; txbNum<3; txbNum++) {
register UWord16* pdT = ioctl(MSCAN_TB, MSCANMG_GET_DATAPTR, NULL);
bflag = 1 << txbNum;
if(ioctl(MSCAN, MSCAN_SELECT_TXBUFF, bflag)){ // Is the current buffer empty?
pdT[0] = outData[0];
pdT[1] = outData[1];
pdT[2] = outData[2]; // outData is defined up top as a global var for now.
pdT[3] = outData[3];
pdT[4] = outData[4];
pdT[5] = outData[5];
pdT[6] = outData[6];
pdT[7] = outData[7];
ioctl(MSCAN, MSCAN_TRANSMIT, bflag);
tEmpty &= ~bflag; // this buffer is no longer empty
}
}
// disable interrupts handled
ioctl(MSCAN, MSCAN_TINT_DISABLE, tEmpty);
}
#pragma interrupt off
//-------------------------------------
static void send_CAN_Pkt(UWord16 outMode, UWord16 txCmd, UWord16 outID, UWord16* sndData) {
static UWord32 outIdCAN;
static UWord16 txbuff;
outData[0] = sndData[0];
outData[1] = sndData[1];
outData[2] = sndData[2];
outData[3] = sndData[3];
outData[4] = sndData[4];
outData[5] = sndData[5];
outData[6] = sndData[6];
outData[7] = sndData[7];
outID = ((ecID << 4) & FROM_MASK) | (outMode << 8); // (1 << 8) is the Mode part. Change to (Mode << 8)
ioctl(MSCAN_TB, MSCANMB_SET_ID, outID);
ioctl(MSCAN_TB, MSCANMB_SET_LEN, 8); // just 8 bytes at the moment
ioctl(MSCAN, MSCAN_TINT_ENABLE, MSCAN_TXEMPTY_ALL); // Enable the interrupt
}
Apologies for the wall of text....
Thanks in advance!
Laurence M
Hi again everyone,
Well, I have figured out what was wrong with my code. A hilarious oversight on my part.
Anyway, for those who might happen to have a similar problem in the future, dont forget to wait and
see if your send buffers are actually empty...
In the send_Can_pkt routine, I had the line:
// Select the next available TX buffer
txbuff = ioctl(MSCAN, MSCAN_SELECT_NEXT_TXBUFF, NULL);
This returns 0 if no buffers are found to be ready. Of course none were found after transmitting 3 blocks of data, so it merrily
returned zero, and would then skip over the if statement and re-enable the TX irq. Which would send the same 3 blocks again.
As a temporary solution, I have used:
while(ioctl(MSCAN, MSCAN_SELECT_NEXT_TXBUFF, NULL) == 0) {
// do nothing
}
// now populate buffers
This works for testing, but opens up the possibility to get stuck in an endless loop, waiting for a buffer to become available.
Now Im off to find a solution for that!
Bye