I'm trying out basic CAN communication on a Hercules microcontroller.

This first test is to test an example project.

Four CAN modules send an 8 char message out to themselves (so that we don't need external hardware).


What's tested here is how to set up CAN and how to use interrupt read-back.




The CAN example


This is the training code that comes with the HALCoGen configuration tool for Hercules.

It uses the controller's internal loop back mechanism to send messages to itself without going external.

This is an inherent part of the safety features of this controller: the ability to verify its own peripherals.

We use it here as part of a demo. In the Hercules safety library, this function is used to validate that the module works and fails safely.



I'm using a Hercules TMS570LC43 LaunchPad. The controller has 4 DAC modules. I enable all.

Then I configure a message sender (1) and receiver (2) for each of the 4 CANs. The message ID for sender and receiver have to be the same (I use 1), otherwise traffic is ignored by the receiver.

Interrupts are enabled on the receivers.

The image shows CAN #2. The setup is the same for all 4.

The high interrupts for the 4 CAN modules have to be enabled in the VIM table.

I'm showing CAN 1 here. It's interrupt 16.

the other ones are on position 35, 45 and 113.


The Code


We use a sender buffer for each of the 4 modules that contains dummy values (not really. It's Jack Kilby Day so I've adapted the content).


#define D_COUNT  8

uint8 tx_data1[D_COUNT] = {'J','a','c','k',' ', ' ',' ',' '};
uint8 tx_data2[D_COUNT] = {'K', 'i', 'l', 'b', 'y', ' ', ' ', ' '};
uint8 tx_data3[D_COUNT] = {'D', 'a', 'y', ' ', ' ', ' ', ' ', ' '};
uint8 tx_data4[D_COUNT] = {31,32,33,34,35,36,37,38};


The receive buffers are empty. At the end of the program they should get the same values as the send buffers.


uint8 rx_data1[D_COUNT] = {0};
uint8 rx_data2[D_COUNT] = {0};
uint8 rx_data3[D_COUNT] = {0};
uint8 rx_data4[D_COUNT] = {0};


At init time, we set the loop-back mode of the 4 CAN modules so that all traffic internally flows from the output to it's own input.


    /** - configuring CAN1 MB1,Msg ID-1 to transmit and CAN2 MB1 to receive */
    canEnableloopback(canREG1, Internal_Lbk);
    canEnableloopback(canREG2, Internal_Lbk);
    canEnableloopback(canREG3, Internal_Lbk);
    canEnableloopback(canREG4, Internal_Lbk);


The only thing the code will do is send the 4 messages. You will not find read functions here. That happens in the interrupt service handler.


    canTransmit(canREG1, canMESSAGE_BOX1, (const uint8 *) &tx_data1[0]);
    canTransmit(canREG2, canMESSAGE_BOX1, (const uint8 *) &tx_data2[0]);
    canTransmit(canREG3, canMESSAGE_BOX1, (const uint8 *) &tx_data3[0]);
    canTransmit(canREG4, canMESSAGE_BOX1, (const uint8 *) &tx_data4[0]);


The ISR receives the info and fills the receive buffers.


void canMessageNotification(canBASE_t *node, uint32 messageBox)  
        canGetData(canREG1, canMESSAGE_BOX2, (uint8 * )&rx_data1[0]); /* copy to RAM */
        canGetData(canREG2, canMESSAGE_BOX2, (uint8 * )&rx_data2[0]); /* copy to RAM */
        canGetData(canREG3, canMESSAGE_BOX2, (uint8 * )&rx_data3[0]); /* copy to RAM */
        canGetData(canREG4, canMESSAGE_BOX2, (uint8 * )&rx_data4[0]); /* copy to RAM */


This is a little exercise that learns how to configure the CAN peripherals. At the end of the program, the content of the receive buffers should be identical to the transmit info.



My next exercise will be to send CAN messages physically from one microcontroller to another.


Project attached. Have a nice Jack Kilby Day!