This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C129xnzad CAN bus

Other Parts Discussed in Thread: TM4C129XNCZAD, TM4C1294NCPDT

Hello,

I am using the TM4C129X development board with the TM4C129XNZAD ARM processor. I have some project working on the board and now I am busy with the CAN bus but I have some problems.

first my setup:

I could send a message with CAN controller 1 but I can't receive any data on CAN controller 1.So when I transmit data over CAN controller 1 the signal on the CAN bus looks like this on the scope:

This is code I used:

tCANBitClkParms CANBitClk;
tCANMsgObject sMsgObjectRx;
tCANMsgObject sMsgObjectTx;
uint8_t pui8BufferIn[8];
uint8_t pui8BufferOut[8];

//enable port T
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOT);
			
//Configure the GPIO pin muxing to select CAN0/1 functions for these pins.
GPIOPinConfigure(GPIO_PT0_CAN0RX);
GPIOPinConfigure(GPIO_PT1_CAN0TX);
GPIOPinConfigure(GPIO_PT2_CAN1RX);
GPIOPinConfigure(GPIO_PT3_CAN1TX);

//enable the alternate function on the GPIO pins.
GPIOPinTypeCAN(GPIO_PORTT_BASE, GPIO_PIN_0);
GPIOPinTypeCAN(GPIO_PORTT_BASE, GPIO_PIN_1);
GPIOPinTypeCAN(GPIO_PORTT_BASE, GPIO_PIN_2);
GPIOPinTypeCAN(GPIO_PORTT_BASE, GPIO_PIN_3);
		
//The GPIO port and pins have been set up for CAN. The can peripheral must be enabled.
SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN1);
	
//
// Reset the state of all the message objects and the state of the CAN
// module to a known state.
//
CANInit(CAN0_BASE);
CANInit(CAN1_BASE);
//
// Configure the controller for 1 Mbit operation.
//
CANBitTimingSet(CAN0_BASE, &CANBitClk);
CANBitTimingSet(CAN1_BASE, &CANBitClk);
//CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 500000);//when used this one, nothing happens on CANbus
//CANBitRateSet(CAN1_BASE, SysCtlClockGet(), 500000);

//
// Take the CAN0 device out of INIT state.
//
CANEnable(CAN0_BASE);
CANEnable(CAN1_BASE);

//
// Configure transmit message object.
//
sMsgObjectTx.ui32MsgID = 0x400;//33;//0x400;
sMsgObjectTx.ui32Flags = MSG_OBJ_NO_FLAGS;
sMsgObjectTx.ui32MsgLen = sizeof(pui8BufferOut);
sMsgObjectTx.pui8MsgData = pui8BufferOut;
	
//
// Configure a receive object.
//
sMsgObjectRx.ui32MsgID = 0x400;
sMsgObjectRx.ui32Flags = MSG_OBJ_NO_FLAGS;
		
while (1){
	CANMessageSet(CAN0_BASE, 1, &sMsgObjectTx, MSG_OBJ_TYPE_TX);
	
	//
	// Wait for new data to become available.
	//
	while((CANStatusGet(CAN1_BASE, CAN_STS_NEWDAT) & 1) == 0)
	{
		//
		// Read the message out of the message object.
		//
		CANMessageGet(CAN1_BASE, 1, &sMsgObjectRx, true);
		UARTprintf("Msg Obj=%u ID=0x%05X len=%u data=0x%d\n", 1,
				sMsgObjectRx.ui32MsgID, sMsgObjectRx.ui32MsgLen, sMsgObjectRx.pui8MsgData);
		}
	}
}

So is there anyone who has ideas what it could be or what I am doing wrong?

Thank you in advance!

Edwin

  • Hello Edwin,

    Just the way you have set the sMsgObjectTx for CAN0, you need to set the sMsgObjectRx for CAN1

    You can refer to the following example code in TivaWare

    C:\ti\TivaWare_C_Series-2.1.0.12573\examples\peripherals\can\simple_rx.c

    Also I had put a code on the forum in last few weeks, for CAN (though it used loopback). Will search it as well and send the link (unless I can get some help from you to search it out)

    Regards

    Amit

  • Hello Amit,
    I found the link on the forum.
    http://e2e.ti.com/support/microcontrollers/tiva_arm/f/908/t/359862.aspx
    I implemented the code and I can send on both controllers. I configured the sMsgObjectRx but I don't get data. The interrupt shows me the following status:
    - Can1 interrupt status: 32768
    - Can1 interrupt status: 1
    The receive code is exact the same as the example you wrote but is not working. I get the same error when receiving from an other CAN board
    Edwin
  • Hello Edwin,

    First of all did you try the code as is to make sure you get both TX and RX functions to work?

    Secondly, do you have a CAN Transceiver connected between the two boards?

    Regards

    Amit

  • Hello Amit,

    The Tx function works. When I use the Tx example on the TI board, I see the correct data on the other board. When I use the transmit of the other board and load the Rx code in the TI board I get the errors. I measured with the scope that the data is on the Rx line so I think it is going wrong in the software but have know idea where.

    I use CAN tranceivers and the bus is closed on both sides with 120 ohm resistors. The CAN bus is working.

    Edwin

  • Hello Edwin,

    I would need a day or two to get the CAN setup with transceivers and test my original code (which was for TM4C123) on TM4C129. If possible, I would share the code so that forum can have a code example to refer to as well.

    Regards

    Amit

  • Hello Edwin,

    I have attached two codes using CAN1 controller for both TX and RX on two independent TM4C129XNCZAD devices. I am using a SN65HV1050 as the CAN Transceiver.

    The RX Code runs on CCSv6 and TX Code runs on CCSv5.5

    You can copy the data from CCSv6 side to a lower CCS Version.

    8738.TM4C129_CAN_RxSide.7z

    8171.TM4C129_CAN_TxSide.7z

    Regards

    Amit

  • Hello Amit,

    Thank you for the code examples. Now it works on my TI board either. Thank you for helping me!

    Edwin

  • hello amit sir
    this above code is not working in ccv7
  • Hello Ashwini

    Which TivaWare version are you using? There is a known issue with can.c driver file in 2.1.3 release for which there is a update on the forum. The fix is coming in the 2.1.4. If you are using 2.1.3 I would suggest using the patch file.
  • hello Amit sir
    i don find the link on forum could you please give me the link.  Also tell me  how to use and install it

  • I am using ubuntu 14.04LTS linux. So suggest in accordance with linux.
  • Hello Ashwini,

    My question was on the TivaWare version!!!
  • hello Amit sir
    yes i am using TivaWare 2.1.3.156 version but i dont find the update for this on forum please help me with link and installation on ubuntu 14.02. simple CAN bus examples from examples/peripherals/can are also are not working in ccs7 .
  • Hello Ashwini

    Following is the thread where you can find the older can.c

    e2e.ti.com/.../1997682
  • hello Amit sir
    i don't find how to build driverlib.lib file as mentioned in e2e.ti.com/.../1997682. driverlib.lib is located at ti/ccv7/driverlib/rvmdk in my system.
  • Hello Ashwini

    You would need to load the driverlib project in your IDE after copying the file can.c
  • Hi Amit,

    I'm facing a somewhat similar issue using TM4C1294NCPDT. It's a new board , so far have got the GPIOs and TCP/IP work as expected, however the CAN refuses to work. I've tried transmitting a message and also just reading the error counter register. It either re-transmits indefinitely or gives a hard fault in the.

    Note: A variant of this code works fine on the obsolete LM3S9B92. The aim is to port the code from our old setup to the new with the TM4C.

    1. During initialization, after setting the CAN baudrate, if I try to run CANBitTimingGet(), the microcontroller goes into a hard microcontroller FaultISR. This occurs just before setting the "synchronous jump width" ui32JW
    2. When a message is transmitted, no message is received and the re-transmission is observed when probed using oscilloscope. Also the Rx pin shows a fixed signal of 70kHz on the Rx line.
    1. CANIntStatus returns 0x00008000
    2. CANStatusGet returns0x00000004
    • When I try to read the the CAN error counter register by CANErrCntrGet() it agains goes into a hard microcontroller FaultISR. This occurs at line 
                  *pui32TxCount = (ui32CANError & CAN_ERR_TEC_M) >> CAN_ERR_TEC_S;

    P.S. Please let me know if I should start a new thread instead of posting here.

      Here's my code:

    void CAN_Init()
    {
    /* Configure CAN Pins Here */

    uint32_t temp;
    tCANBitClkParms *CANBitClk2;

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinConfigure(GPIO_PA0_CAN0RX);
    GPIOPinConfigure(GPIO_PA1_CAN0TX);
    GPIOPinTypeCAN(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    /* Enable the CAN controller*/
    SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);

    /* Reset the state of all the message objects and the state of the CAN */
    /* module to a known state. */
    CANInit(CAN0_BASE);

    temp = CANBitRateSet(CAN0_BASE, g_ui32SysClock, CAN0_BaudRate);
    CANBitTimingGet(CAN0_BASE,CANBitClk2);                                                         /////// HARD FAULT OCCURS HERE . If commented uC gets through the init ////////

    CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);

    //
    // Enable the CAN interrupt on the processor (NVIC).
    //
    IntEnable(INT_CAN0);

    //
    // Enable the CAN for operation.
    //
    CANEnable(CAN0_BASE);

    //
    // Initialize a message object to be used for receiving CAN messages with
    // any CAN ID. In order to receive any CAN ID, the ID and mask must both
    // be set to 0, and the ID filter enabled.
    //
    sMsgObjectRx.ui32MsgID = 0; // CAN msg ID - 0 for any
    sMsgObjectRx.ui32MsgIDMask = 0; // mask is 0 for any ID
    sMsgObjectRx.ui32Flags = (MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER) ;
    sMsgObjectRx.ui32MsgLen = 8; // allow up to 8 bytes

    CANMessageSet(CAN0_BASE, RX_BUFFER_OBJID, &sMsgObjectRx, MSG_OBJ_TYPE_RX);

    }

    /*----------------------------------------------------------------------------
    * ISR - CAN Interrupt Service Routine
    *---------------------------------------------------------------------------*/
    void CANIntHandler (void)
    {
    unsigned long ulStatus; /*interrupt status register*/

    /*Read the CAN interrupt status to find the cause of the interrupt*/
    ulStatus = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);
    /* If the cause is a controller status interrupt, then get the status*/
    if(ulStatus == CAN_INT_INTID_STATUS)
    {
    /* Error Handling Not fully implemented yet RC-TODO!*/
    /*NOTE: If Micro is not connected to an external CAN device, Errors will be generated*/
    ulStatus = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);                                       /////// On transmitting  ////////
    /*Flag Error present*/
    g_bErrFlag = 1;
    }
    /*check for rx Interrupt*/
    else if(ulStatus == RX_BUFFER_OBJID)
    {
    /*RX interrupt occurred and the message RX is complete.*/
    /*Clear the message object interrupt.*/
    CANIntClear(CAN0_BASE, RX_BUFFER_OBJID);
    /* Increment msg counter*/
    g_ulMsgCount++;
    /*clear any error flags.*/

    /* GW Stolen from example*/
    g_bRXFlag = 1;

    g_bErrFlag = 0;
    }
    else
    {
    // let's see if we are getting ANY interrupts...
    g_ulMsgCount = 321;
    /*Spurious interrupt, should never happen, implement handing RC-TODO!*/
    }
    }

    Thanks

    Amrita

  • Hello Amrita

    Which version of TivaWare are you using?
  • Hi Amit,

    Thanks​ for a prompt response.

    I was using 2.1.3 but upgraded to 2.1.4 after looking at this post yesterday. But, no change in the CAN behavior.

    Amrita

  • Hello Amrita,

    I ran with 2.1.4 the can example code and it works fine. Did you make sure that you recompiled the entire code base and checked if the linker path for the driverlib.lib also maps to the 2.1.4 ?
  • Hi Amit,

    CAN works now. There were a few issues:

    1. The clock used was 50MHz (like our previous LM3S) but figured it has to be a integer multiple of 480 so brought it down to 48MHz (This was found not to be an issue once the #2 below was addressed - but does affect hard timers since they run based on 48MHz even if configCPU_CLOCK_HZ is set as 50MHz)

    2. The crystals mounted were swapped. 25MHz for the processor clock and 16MHz for ethernet instead of the other way around. So basically the retransmission was occuring because the expected and actual baudrate were 40% apart.

    3. The hard fault in CanBitTimingGet error was due to the way the the pointers were used. The pointers were pointing to address zero and hence the hard fault. tCANBitClkParms CANBitClk works with the new compiler and tCANBitClkParms *CANBitClk works with the old. The exact reason is unknown but I think it's related to the updated compiler. Same pointer usage issue with CANErrCntrGet() 

    Thanks for your help - to have someone at TI for a sanity check is always reassuring.

    Amrita

  • Amrita said:
    ...figured it has to be a integer multiple of 480 so brought it down to 48MHz

    Might you (a bit) detail why you, "so figured?"    Firm/I have run CAN successfully @ both 50 & 40MHz - from where did the "480 factor" arise?

    Indeed - vendor's skilled assistance is, "Worth its weight in gold."    Glad that you persisted & achieved your MCU migration successfully.    (we've done the same: LM3S to 4C123.)

  • Hi cb1_mobile

    Here's how I "figured" e2e.ti.com/.../1346087

    It does work with 50MHz as well, now that the crystal oscillator frequency is corrected.

    Amrita

  • Aha - the "480" parameter is required w/129x devices - when seeking (I believe) 30, 40, 48, 60, 80, 96 or 120 MHz (semi-standard) system clocks.   (i.e.  480 best accepts "multiple" integer dividers - yet 360 (chosen for degrees w/in a circle) is more universal & "standard.")

    As we use 123 devices - the "480" value does not apply - and (never) had we seen (any) reference to 480 as a requirement for CAN frequency determination.

    Thank you & good luck...