DESIGN CYCLE
■ FIGURE 3. The trick
to understanding
how the PIC32MX
CAN peripheral
library-based CAN
transmission
mechanism works is
to think in 32-bit
words organized as
four eight-bit bytes.
We’re not pointing
to anything yet. We’ve
only assigned a
pointer to the
CANTxMessageBuffer
structure. So, let’s
make sure we’re
pointing at a valid transmit message buffer:
Ever hear the sound of bits travelling down a wire?
WHOOSH!!!!
message = CANGetTxMessageBuffer
(CAN2,CAN_CHANNEL0);
RECEIVING A CAN MESSAGE
Now we’re pointing at a message buffer in Channel 0
which happens to be our transmit channel. A NULL
returned to message means that we don’t have a valid
message buffer in our grasp. If we are truly pointing to a
transmit message buffer in Channel 0, we can proceed
with our transmission process. The first order of business is
to build a CAN SID message. Before we can do that, we
should clear the land so to speak. That’s where the
message Word array comes into play:
if(message != NULL)
{
//clear the Message Buffer
message->messageWord[0] = 0;
message->messageWord[1] = 0;
message->messageWord[2] = 0;
message->messageWord[3] = 0;
Let’s send a SID CAN message that contains one byte
of data payload to a CAN node with the address of
0x101. Just for grins, let’s make the payload byte an ASCII
character that we can print and read in a terminal
emulator. How about 0x41, which is an ASCII ‘A:’
message->msgSID.SID = 0x101;
message->msgEID.IDE = 0;
message->msgEID.DLC = 1;
message->data[0] = 0x41;
We are pointing to the members of the pointed-to
structure CANTxMessageBuffer and filling the members
with our desired data. Note that the IDE is cleared
indicating a SID message and the DLC field reflects the
data payload length of one byte. We’ve posted our CAN
message in a valid message buffer. Before we do anything
else, we need to update the message buffer’s internal
pointers and send the message:
CANUpdateChannel(CAN2,CAN_CHANNEL0);
CANFlushTxChannel(CAN2,CAN_CHANNEL0);
}
The interrupt handler we mentioned earlier is the first
to know that a valid CAN message has been received.
After the CAN receive interrupt fires, the CAN receive
interrupt handler determines what caused the interrupt
and branches accordingly. In our case, Channel 1 will be
found to be the cause of the interrupt receive event. To
prevent the receive interrupt from triggering again before
we have time to service the original receive event, we
must disable the receive interrupt trigger. We can then
inform the application that a CAN message has been
received via a flag, clear the receive interrupt flag, and
return to the application. Here is what I just said translated
to code:
void __attribute__((vector(47), interrupt(ipl4),
nomips16)) CAN2InterruptHandler(void)
{
if((CANGetModuleEvent(CAN2) & CAN_RX_EVENT)
!= 0)
{
if(CANGetPendingEventCode(CAN2) ==
CAN_CHANNEL1_EVENT)
{
CANEnableChannelEvent(CAN2, CAN_CHANNEL1,
CAN_RX_CHANNEL_NOT_EMPTY, FALSE);
isCAN2MsgReceived = TRUE;
}
}
INTClearFlag(INT_CAN2);
}
The CAN receive message algorithm is similar to
the transmit message except we are taking instead
of giving from a message buffer point of view. We
still have to assign a pointer to the receive message
buffer:
November 2011 73