I'm attempting to use a simple processor and a MCP2515 CAN controller over SPI communication. I have no problems sending or receiving single frame CAN messages. However, when I try either global BAM messaging or using the Transport Protocol, I cannot get the multiframe data through to the other side.
Example:
- Transport Protocol J1939 / ISO11783, send TP announcement message PDU 236 (RTS)- with number bytes and number packets required, say 10 packets.
- Receive TP clear to send (CTS) PDU 236 from receiver with OK and flagged to send all 10 packets.
- I then send each packet in PDU 235 frames, (tried with varying time delays from 0 to 200 msec).
- Then a short time with no response, then I get PDU 236 with ABORT code and reason timeout.
Now I thought about the MCP2515 having 3 send buffers. Perhaps as I loaded them they were sent out of sequence. So I modified the code to use buffer[0]
on the MCP2515 only by waiting until that buffer is flagged as empty before loading the next frame. This should make frame sequence a certainty.
Any leads here would be appreciated. The goal is simply to get the receiving end (which is any number of manufacturer display systems) to read the data and send a EOF response showing the data was received. This is not happening as of now.
//function to organize and send multi-packets with flow control protocol
bool ISO11783DATA::sendTPCM(byte reqADDR, byte* buff, uint16_t noBytes, uint32_t PGN, byte priority)
{
if(busONstate == true)
{
RECEIVE_CTS cts;
MFMESSOUT outmess;
//load frames
uint8_t noFrames = outmess.loadBuffers(buff, noBytes);
uint16_t byteCounter = 0;
cts.PGN = PGN; //set to compare with rx messages
ISO_TPCM_RTS(reqADDR, noFrames, noBytes, PGN, priority); //announce multiframe header
if(*diagnostics == true)
{
informln(F("sent TCPM announcement"));
inform(F("noFrames= ")); inform(noFrames); inform(F(" noBytes= ")); informln(noBytes);
}
bool clearToSend = false;
bool messageComplete = false;
unsigned long timeOUT = millis(); //break timer
while(messageComplete == false)
{
if( millis()-timeOUT > 3000UL)//1250UL) //time out break
{
ISO_TPCM_ABORT(reqADDR, priority, PGN);
if(*diagnostics == true){informln(F("tcpm send timeout error"));}
return false;
}
if(clearToSend == true) //load next frame and send
{
clearToSend = false;
uint8_t frameIndex = cts.next2Send-1;//if says send#1 send index 0
for(uint8_t cntout = 0; cntout<cts.no2Send; cntout++)
{
byte bytesInMessage = 7;
if( frameIndex == cts.no2Send-1 ){bytesInMessage = outmess.noInLastFrame;}
if(*diagnostics == true)
{
inform(F("sending multipacket data number ")); informln(frameIndex+1);
inform("no in this frame ="); informln(bytesInMessage);
//inform("no in last frame ="); informln(outmess.noInLastFrame);
byteCounter += bytesInMessage;
inform(F("sent bytes= ")); informln(byteCounter);
}
ISO_TP_DATA(reqADDR, frameIndex+1, bytesInMessage+1, outmess.data[frameIndex], priority); //send packet
frameIndex++; //send number it allowed then wait for CTS again
timeOUT = millis();
//if(cts.no2Send > 1 && cntout<cts.no2Send){delay(10);} //only delay till next send time unless done
}
}//end CST true
//listen for CTS EOF or ABORT
if(pCAN0->available() > 0 ){pCAN0->readCANbus();}//checks int pin reads in and flags can buffers
for(int n=0; n<numberCanBuffers; n++)
{
if(pCAN0->isoFrame[n].newData == true)
{
pCAN0->isoFrame[n].newData= false;
int action = ID_CAN_MESSAGEinloop( pCAN0->isoFrame[n], cts ); //checks data in frame now, returns new cts info if multiframe response, since waiting must not initiate another multiframe
if(action == CTS && cts.PGN == PGN) //filters so response is for this node and tx message
{
timeOUT = millis(); //reset timeout since new rx message
clearToSend = true; //ready to send more
}
if(action == EOF && cts.PGN == PGN)
{
timeOUT = millis();//reset timeout since new rx message
messageComplete = true;
//inform("noByes "); inform(cts.bytesReceived); inform("\tnoPackets "); inform(cts.packetsReceived); inform("\PGN "); informln(cts.PGN);
return true;
}
if(action == ABORT && cts.PGN == PGN)
{
inform("ordered Abort "); informln(cts.PGN);
return false;
}
}
}//end for check rx buffers
}//end while mess complete false loop
}//end if bus on
return false;
}//end TCPM
//---------------------------------------------------------------------
//returns to state ability to load tx buffer mcp2515
bool ISO11783DATA::send_singleFrame_Buff(byte* buf, byte priority, byte PDUF, byte PDUS, byte datalength, byte datapage, int TXindex)
{
unsigned long timeout = millis();
CAN_ID_t out;
out.PRIORITY = priority;
out.extDATAPAGE = 0;
out.DATAPAGE = datapage;
out.PDU_FORMAT = PDUF;
out.PDU_SPECIFIC = PDUS;
if(nodeADDRresolved == true){out.SRC_ADDR = nodeADDR;}
else{out.SRC_ADDR = 254;}
out.DATA_LENGTH = datalength;
out.RTR = 0;
out.IDExt = 1; //true
out.buffer[0] = buf[0];
out.buffer[1] = buf[1];
out.buffer[2] = buf[2];
out.buffer[3] = buf[3];
out.buffer[4] = buf[4];
out.buffer[5] = buf[5];
out.buffer[6] = buf[6];
out.buffer[7] = buf[7];
//check if buffer ready
while(pCAN0->sendFrame(out, TXindex) == false)
{
if(millis() - timeout >= 1250UL){return false;}
}
return true;
}//end send single frame from selected mcp2515 txbuff
//-----------------------------------------------------------------------
bool MPC2515CANBUS::sendFrame(CAN_ID_t struc, int index)
{
byte buffer[14];
if(struc.IDExt > 0)
{
encode_CAN_TxBufferExtended(buffer, (byte)struc.PRIORITY, (byte)struc.extDATAPAGE, (byte)struc.DATAPAGE, (byte)struc.PDU_FORMAT, (byte)struc.PDU_SPECIFIC,
(byte)struc.SRC_ADDR, struc.RTR, (byte)struc.DATA_LENGTH,
struc.buffer[7], struc.buffer[6],struc.buffer[5],struc.buffer[4],struc.buffer[3],struc.buffer[2],struc.buffer[1],struc.buffer[0]);
}
if(struc.IDExt == 0)
{
encode_CAN_TxBufferStandard(buffer, (unsigned int)struc.PGN, (byte)struc.SRC_ADDR, struc.RTR, (byte)struc.DATA_LENGTH,
struc.buffer[7], struc.buffer[6],struc.buffer[5],struc.buffer[4],struc.buffer[3],struc.buffer[2],struc.buffer[1],struc.buffer[0]);
}
return sendCANmessage(buffer, index);
}
//------------------------------------------------------
bool MPC2515CANBUS::sendCANmessage(byte* buffer, int index)
{
if(checkCANTXbuf(index) != 0) //buffer not yet sent // function checks flag bit to see if buffer is empty or not
{
informln("txbuff not ready");
return false;
}
byte ADDR;
if(index == 0){ADDR = 0x31;}
if(index == 1){ADDR = 0x41;}
if(index == 2){ADDR = 0x51;}
digitalWrite(CS_can, LOW);
SPI.transfer(WRITE);
SPI.transfer(ADDR);
for(int n=0; n<13; n++){SPI.transfer(buffer[n]);}
digitalWrite(CS_can, HIGH);
RTSbuffer(index);
return true;
}
//---------------------------------------------------------------------