I've been working on a breadboarded BoosterPack to test the CAN modules on the TI Hercules LaunchPad, without transceivers or real CAN bus.

Photo 13-12-14 18 19 37.jpg

This is inspired by the following Siemens application note AP2921 On-Board Communication via CAN without Transceiver.
The example allows you to run and probe the canIntCommunication example from HALCoGen by using 1 resistor, 2 diodes, some wire and a breadboard.

For learning use only. This design is not intended for use outside your lab. See this design for a fully functional CAN bus.

 

EXPERIENCE ZONE:

  • Automotive: My design facilitates investigating the automotive CAN protocol.

PROJECT FEATURES:

  • Learn CAN with your LaunchPad and a few passive components
  • the CAN1 and CAN2 module on your LaunchPad can talk to each other - just like with the bigger development boards
  • You can probe the signals with oscilloscope and logic analyzer
  • Low entry point to experiment with CAN

 


 

The poor man's can bus

 

A proper CAN implementation uses tranceivers and twisted pair wiring. And in an automotive setting I would not use anything different.

But for experimenting purposes, there's a simpler solution. You can replace a driver by a single diode on the transmit line:

canScan.jpg

 

The launchpad has 2 CAN modules, but no driver. In a test setting, that driver is not really needed.

Send and Receive of all CAN devices use the same single wire. The only thing we have to take care of is that the send lines don't conflict.

A simple isolation diode does the job. It takes care that a transmit line can drive the line without having to fight with the line's level.

If there's a conflict between senders, the diode takes care that it doesn't result in overload of the CAN peripheral.

breadboard.jpg

Code

 

I use HALCoGen's canIntCommunication example.

The only change I've made is to place the canMessageNotification() function in notification.c in stead of in sys_main.c, because it belongs there.

 

sys_main.c:

// ...
/* USER CODE BEGIN (1) */
#include "can.h"
#include "esm.h"
#include "sys_core.h"


#define D_COUNT  8


uint32 cnt=0, error =0, tx_done =0;
uint8 tx_data[D_COUNT][8] = {0};
uint8 rx_data[D_COUNT][8] = {0};
uint8 *tx_ptr = &tx_data[0][0];
uint8 *rx_ptr = &rx_data[0][0];
uint8 *dptr=0;


void dumpSomeData();
/* USER CODE END */







// ..// ....





 

void main(void)
{
/* USER CODE BEGIN (3) */


    /* enable irq interrupt in Cortex R4 */
    _enable_interrupt_();


    /** - writing a random data in RAM - to transmit */
    dumpSomeData();


    /** - configuring CAN1 MB1,Msg ID-1 to transmit and CAN2 MB1 to receive */
    canInit();


    /** - enabling error interrupts */
    canEnableErrorNotification(canREG1);
  canEnableErrorNotification(canREG2);


    /** - starting transmission */
     for(cnt=0;cnt<D_COUNT;cnt++)
    {
      canTransmit(canREG1, canMESSAGE_BOX1, tx_ptr); /* transmitting 8 different chunks 1 by 1 */
      while(tx_done == 0){};                 /* ... wait until transmit request is through        */
      tx_done=0;
      tx_ptr +=8;    /* next chunk ...*/
    }


    /** - check the received data with the one that was transmitted */
    tx_ptr = &tx_data[0][0];
    rx_ptr = &rx_data[0][0];


    for(cnt=0;cnt<63;cnt++)
     {
          if(*tx_ptr++ != *rx_ptr++)
          {
               error++; /* data error */
          }
     }


    while(1){}; /* wait forever after tx-rx complete. */


/* USER CODE END */
}


/* USER CODE BEGIN (4) */
/* writing some data to ram  */
void dumpSomeData()
{
     uint32 tmp = 0x11;


     cnt = (D_COUNT*8)-1;
     dptr = &tx_data[0][0];
     *dptr = tmp;


     while(cnt--)
     {
        tmp = *dptr++;
        *dptr = tmp + 0x11;
     }
}




/* can interrupt notification */
/* Note-You need to remove canMessageNotification from notification.c to avoid redefinition */


// jc: moved to notification.c




/* USER CODE END */



 

 

notification.c:

/* USER CODE BEGIN (0) */
extern uint32 tx_done;
extern uint8 *rx_ptr;


/* USER CODE END */



...

#pragma WEAK(canMessageNotification)
void canMessageNotification(canBASE_t *node, uint32 messageBox)
{
/*  enter user code between the USER CODE BEGIN and USER CODE END. */
/* USER CODE BEGIN (15) */
    /* node 1 - transfer request */
    if(node==canREG1)
    {
      tx_done=1; /* confirm transfer request */
    }


    /* node 2 - receive complete */
    if(node==canREG2)
    {
     while(!canIsRxMessageArrived(canREG2, canMESSAGE_BOX1));
     canGetData(canREG2, canMESSAGE_BOX1, rx_ptr); /* copy to RAM */
     rx_ptr +=8;
    }


   /* Note: since only message box 1 is used on both nodes we dont check it here.*/
/* USER CODE END */
}



 

Result

 

Here's a sample taken with my protocol analyzer (a Papilio Pro loaded with the LogicSniffer design, with OpenLogic Sniffer as client):

ols.jpg

 

Nothing spectacular here. But it's now possible to start digging into the CAN protocol with the Hercules LaunchPad without additional investment. A few scrap parts will do.