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.

TM4C1294NCPDT: CAN message between two TM4C1294NCPDT

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: EK-TM4C1294XL

Hello Everyone!
I'm very new to TM4C and the Can protocol and actually embedded software.
For my job, I need to communicate with CAN protocol between two TM4C1294 as master and slave. While surfing the internet, I found a code on this site.

(  ohm.ninja/.../ ) I set up the circuit as shown on the site.

However, when it comes to the code part, I have some problems.

This is my code on the Master(transmitter) side:

#include <stdio.h>
#include <stdbool.h>
#include <math.h>
#include <stdint.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_can.h"
#include "inc/hw_ints.h"
#include "driverlib/can.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "driverlib/pin_map.h"

#include "utils/uartstdio.h"
#include "utils/uartstdio.c"

#define PI 3.14159265359f

volatile bool errFlag = 0; // transmission error flag
unsigned int sysClock; // clockspeed in hz

void delay(unsigned int milliseconds) {
SysCtlDelay((sysClock / 3) * (milliseconds / 1000.0f));
}

// CAN interrupt handler
void CANIntHandler(void) {

unsigned long status = CANIntStatus(CAN1_BASE, CAN_INT_STS_CAUSE); // read interrupt status

if(status == CAN_INT_INTID_STATUS) { // controller status interrupt
status = CANStatusGet(CAN1_BASE, CAN_STS_CONTROL); // read back error bits, do something with them?
errFlag = 1;
} else if(status == 1) { // message object 1
CANIntClear(CAN1_BASE, 1); // clear interrupt
errFlag = 0; // clear any error flags
} else { // should never happen
UARTprintf("Unexpected CAN bus interrupt\n");
}
}

int main(void) {

tCANMsgObject msg; // the CAN message object
unsigned int msgData; // the message data is four bytes long which we can allocate as an int32
unsigned char *msgDataPtr = (unsigned char *)&msgData; // make a pointer to msgData so we can access individual bytes

// Run from the PLL at 120 MHz.
sysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);

// Set up debugging UART
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // enable UART0 GPIO peripheral
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
UARTStdioConfig(0, 115200, sysClock); // 115200 baud

// Set up CAN1
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); // enable CAN1 GPIO peripheral
GPIOPinConfigure(GPIO_PB0_CAN1RX);
GPIOPinConfigure(GPIO_PB1_CAN1TX);
GPIOPinTypeCAN(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN1);
CANInit(CAN1_BASE);
CANBitRateSet(CAN1_BASE, sysClock, 500000);
CANIntRegister(CAN1_BASE, CANIntHandler); // use dynamic vector table allocation
CANIntEnable(CAN1_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
IntEnable(INT_CAN1);
CANEnable(CAN1_BASE);

// Set up msg object
msgData = 0;
msg.ui32MsgID = 1;
msg.ui32MsgIDMask = 0;
msg.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
msg.ui32MsgLen = sizeof(msgDataPtr);
msg.pui8MsgData = msgDataPtr;

unsigned int t = 0; // loop counter
float freq = 0.3; // frequency scaler

while(1) {

// set up next colour (scale sinf (0-1) to 0-255)
msgDataPtr[0] = (0.5 + 0.5*sinf(t*freq)) * 0xFF;
msgDataPtr[1] = (0.5 + 0.5*sinf(t*freq + (2*PI/3))) * 0xFF; // 120 degrees out of phase
msgDataPtr[2] = (0.5 + 0.5*sinf(t*freq + (4*PI/3))) * 0xFF; // 240 degrees out of phase
msgDataPtr[3] = 128; // 50% intensity */

UARTprintf("Sending colour\tr: %d\tg: %d\tb: %d\n", msgDataPtr[0], msgDataPtr[1], msgDataPtr[2]); // write colour to UART for debugging
CANMessageSet(CAN1_BASE, 1, &msg, MSG_OBJ_TYPE_TX); // send as msg object 1

delay(100); // wait 100ms

if(errFlag) { // check for errors
UARTprintf("CAN Bus Error %d\n", errFlag);
}

t++; // overflow is fine
}

//return 0;
}

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------

First of all on the master side my CAN message is not transmitting. As you see there is a CAN Bus Error Flag is 1.

Before turn my head to the receiving side, what could be the problem of my transmitting code? What I need to change?

I haven't had a chance to measure outputs with the oscilloscope yet.

Actually, I saw a title on a similar topic before, but things were a bit too complicated for me there. I wonder if anyone can help me in this area more easily?

  • Hi,

      I don't  really spot anything wrong with the code. It is very likely that your transmitter is not connected to the CAN bus network resulting with the error. 

      - Do you have the transceiver on the CAN network?

      - Do you have at least two nodes on the CAN network. You can't just have one node (e.g. only a transmitter) on the network. 

      - Can you probe the PB1 pin which is the CAN1TX? Do you see any activities on PB1 pin? Do the same on the TxD input to the transceiver. Make sure you have proper connection.

      - Probe the CAN_H and CAN_L from the transceiver. These two are the differential signals for the CAN. If you see TxD activities but don't see activities on the CAN_H and CAN_L then you need to check the transceiver. Do you proper power supply to the xceiver and etc. 

      - Does the receiver node have the same bit rate as the transmitter which is configured for 500k?

  • Hello Charles

    - Do you have the transceiver on the CAN network?

      - Do you have at least two nodes on the CAN network. You can't just have one node (e.g. only a transmitter) on the network. 

    Yes I have two MCP2551s and they are connected just like in the schematic.

    - Can you probe the PB1 pin which is the CAN1TX? Do you see any activities on PB1 pin? Do the same on the TxD input to the transceiver. Make sure you have proper connection.

    I have measured both PB1 and TxD pins and it gives a constant output of about 3.3V and it does not seem to sending any message.

    - Probe the CAN_H and CAN_L from the transceiver. These two are the differential signals for the CAN. If you see TxD activities but don't see activities on the CAN_H and CAN_L then you need to check the transceiver. Do you proper power supply to the xceiver and etc. 

    I probe CAN_H and CAN_L and following picture is shown differential signal. Seems like nothing here. I am feeding both mcp2551s with 5V from TI launchpads.

    - Does the receiver node have the same bit rate as the transmitter which is configured for 500k?

    I haven't download the code for the receiver side yet. because in the original project he uses tm4c123 for the receiver and sends the CAN message to light the RGB LEDs. But I use two TM4c1294 as a receiver and transmitter and all I want to communicate these two MCU's as a MASTER and SLAVE. 

    When I see the MASTER sending CAN message properly then I'll download the SLAVE parts code to the SLAVE MCU.

    By the way the link of the page with the original code is not visible in my first message, so I'm resending it.

    https://ohm.ninja/tiva-c-series-can-bus-with-mcp2551/

  • Hi,

      That is weird. I don't know what is the problem. Can you try this example? This example use CAN0 instead of CAN1? On the LaunchPad you need to change both the J4 and J5 jumpers from their horizontal positions to vertical positions. You will need to map your UARTprintf to UART2. Please refer to the EK-TM4C1294XL launchPad user's guide for details. 

    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_can.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/can.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"

    //*****************************************************************************
    //
    //! \addtogroup can_examples_list
    //! <h1>Simple CAN TX (simple_tx)</h1>
    //!
    //! This example shows the basic setup of CAN in order to transmit messages
    //! on the CAN bus. The CAN peripheral is configured to transmit messages
    //! with a specific CAN ID. A message is then transmitted once per second,
    //! using a simple delay loop for timing. The message that is sent is a 4
    //! byte message that contains an incrementing pattern. A CAN interrupt
    //! handler is used to confirm message transmission and count the number of
    //! messages that have been sent.
    //!
    //! This example uses the following peripherals and I/O signals. You must
    //! review these and change as needed for your own board:
    //! - CAN0 peripheral
    //! - GPIO Port A peripheral (for CAN0 pins)
    //! - CAN0RX - PA0
    //! - CAN0TX - PA1
    //!
    //! This example uses the following interrupt handlers. To use this example
    //! in your own application you must add these interrupt handlers to your
    //! vector table.
    //! - INT_CAN0 - CANIntHandler
    //
    //*****************************************************************************

    //*****************************************************************************
    //
    // A counter that keeps track of the number of times the TX interrupt has
    // occurred, which should match the number of TX messages that were sent.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32MsgCount = 0;

    //*****************************************************************************
    //
    // A flag to indicate that some transmission error occurred.
    //
    //*****************************************************************************
    volatile bool g_bErrFlag = 0;

    //*****************************************************************************
    //
    // This function provides a 1 second delay using a simple polling method.
    //
    //*****************************************************************************
    void
    SimpleDelay(void)
    {
    //
    // Delay cycles for 1 second
    //
    SysCtlDelay(16000000 / 3);
    }

    //*****************************************************************************
    //
    // This function is the interrupt handler for the CAN peripheral. It checks
    // for the cause of the interrupt, and maintains a count of all messages that
    // have been transmitted.
    //
    //*****************************************************************************
    void
    CANIntHandler(void)
    {
    uint32_t ui32Status;

    //
    // Read the CAN interrupt status to find the cause of the interrupt
    //
    ui32Status = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);

    //
    // If the cause is a controller status interrupt, then get the status
    //
    if(ui32Status == CAN_INT_INTID_STATUS)
    {
    //
    // Read the controller status. This will return a field of status
    // error bits that can indicate various errors. Error processing
    // is not done in this example for simplicity. Refer to the
    // API documentation for details about the error status bits.
    // The act of reading this status will clear the interrupt. If the
    // CAN peripheral is not connected to a CAN bus with other CAN devices
    // present, then errors will occur and will be indicated in the
    // controller status.
    //
    ui32Status = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);

    //
    // Set a flag to indicate some errors may have occurred.
    //
    g_bErrFlag = 1;
    }

    //
    // Check if the cause is message object 1, which what we are using for
    // sending messages.
    //
    else if(ui32Status == 1)
    {
    //
    // Getting to this point means that the TX interrupt occurred on
    // message object 1, and the message TX is complete. Clear the
    // message object interrupt.
    //
    CANIntClear(CAN0_BASE, 1);

    //
    // Increment a counter to keep track of how many messages have been
    // sent. In a real application this could be used to set flags to
    // indicate when a message is sent.
    //
    g_ui32MsgCount++;

    //
    // Since the message was sent, clear any error flags.
    //
    g_bErrFlag = 0;
    }

    //
    // Otherwise, something unexpected caused the interrupt. This should
    // never happen.
    //
    else
    {
    //
    // Spurious interrupt handling can go here.
    //
    }
    }

    //*****************************************************************************
    //
    // Configure the CAN and enter a loop to transmit periodic CAN messages.
    //
    //*****************************************************************************
    int
    main(void)
    {
    #if defined(TARGET_IS_TM4C129_RA0) || \
    defined(TARGET_IS_TM4C129_RA1) || \
    defined(TARGET_IS_TM4C129_RA2)
    uint32_t ui32SysClock;
    #endif

    tCANMsgObject sCANMessage;
    uint32_t ui32MsgData;
    uint8_t *pui8MsgData;

    pui8MsgData = (uint8_t *)&ui32MsgData;

    //
    // Set the clocking to run directly from the external crystal/oscillator.
    // TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
    // crystal on your board.
    //
    #if defined(TARGET_IS_TM4C129_RA0) || \
    defined(TARGET_IS_TM4C129_RA1) || \
    defined(TARGET_IS_TM4C129_RA2)
    #if 0
    ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
    SYSCTL_OSC_MAIN |
    SYSCTL_USE_OSC),
    25000000);
    #else
    //
    // Run from the PLL at 120 MHz.
    //
    ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
    SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
    SYSCTL_CFG_VCO_480), 120000000);

    #endif

    #else
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
    SYSCTL_XTAL_16MHZ);
    #endif

    //
    // For this example CAN0 is used with RX and TX pins on port A0 and A1.
    // The actual port and pins used may be different on your part, consult
    // the data sheet for more information.
    // GPIO port B needs to be enabled so these pins can be used.
    // TODO: change this to whichever GPIO port you are using
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Configure the GPIO pin muxing to select CAN0 functions for these pins.
    // This step selects which alternate function is available for these pins.
    // This is necessary if your part supports GPIO pin function muxing.
    // Consult the data sheet to see which functions are allocated per pin.
    // TODO: change this to select the port/pin you are using
    //
    GPIOPinConfigure(GPIO_PA0_CAN0RX);
    GPIOPinConfigure(GPIO_PA1_CAN0TX);

    //
    // Enable the alternate function on the GPIO pins. The above step selects
    // which alternate function is available. This step actually enables the
    // alternate function instead of GPIO for these pins.
    // TODO: change this to match the port/pin you are using
    //
    GPIOPinTypeCAN(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // The GPIO port and pins have been set up for CAN. The CAN peripheral
    // must be enabled.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);

    //
    // Initialize the CAN controller
    //
    CANInit(CAN0_BASE);

    //
    // Set up the bit rate for the CAN bus. This function sets up the CAN
    // bus timing for a nominal configuration. You can achieve more control
    // over the CAN bus timing by using the function CANBitTimingSet() instead
    // of this one, if needed.
    // In this example, the CAN bus is set to 500 kHz. In the function below,
    // the call to SysCtlClockGet() or ui32SysClock is used to determine the
    // clock rate that is used for clocking the CAN peripheral. This can be
    // replaced with a fixed value if you know the value of the system clock,
    // saving the extra function call. For some parts, the CAN peripheral is
    // clocked by a fixed 8 MHz regardless of the system clock in which case
    // the call to SysCtlClockGet() or ui32SysClock should be replaced with
    // 8000000. Consult the data sheet for more information about CAN
    // peripheral clocking.
    //
    #if defined(TARGET_IS_TM4C129_RA0) || \
    defined(TARGET_IS_TM4C129_RA1) || \
    defined(TARGET_IS_TM4C129_RA2)
    CANBitRateSet(CAN0_BASE, ui32SysClock, 500000);
    #else
    CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 500000);
    #endif

    //
    // Enable interrupts on the CAN peripheral. This example uses static
    // allocation of interrupt handlers which means the name of the handler
    // is in the vector table of startup code. If you want to use dynamic
    // allocation of the vector table, then you must also call CANIntRegister()
    // here.
    //
    // CANIntRegister(CAN0_BASE, CANIntHandler); // if using dynamic vectors
    //
    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 the message object that will be used for sending CAN
    // messages. The message will be 4 bytes that will contain an incrementing
    // value. Initially it will be set to 0.
    //
    ui32MsgData = 0;
    sCANMessage.ui32MsgID = 1;
    sCANMessage.ui32MsgIDMask = 0;
    sCANMessage.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
    sCANMessage.ui32MsgLen = sizeof(pui8MsgData);
    sCANMessage.pui8MsgData = pui8MsgData;

    //
    // Enter loop to send messages. A new message will be sent once per
    // second. The 4 bytes of message content will be treated as an uint32_t
    // and incremented by one each time.
    //
    while(1)
    {
    //
    // Send the CAN message using object number 1 (not the same thing as
    // CAN ID, which is also 1 in this example). This function will cause
    // the message to be transmitted right away.
    //
    CANMessageSet(CAN0_BASE, 1, &sCANMessage, MSG_OBJ_TYPE_TX);

    //
    // Now wait 1 second before continuing
    //
    SimpleDelay();

    //
    // Check the error flag to see if errors occurred
    //
    if(g_bErrFlag)
    {
    }
    else
    {
    //
    // Increment the value in the message data.
    //
    ui32MsgData++;
    }

    }

    //
    // Return no errors
    //
    return(0);
    }

  • Hello Charles.

    I moved the J4 and J5 from horizontal to vertical position. I download the code you gave but when I checked the signal on the PA1 with probe it's constant 3.3V. And also nothing seems in the Terminal.

    You will need to map your UARTprintf to UART2.

    I wonder do I need to change anything in header files or main code for map UARTprintf to UART2?

  • Sorry, I forgot to say this example does not use UARTprintf. It is weird that you don't see anything on CAN0TX. Do you have another launchPad that you can try.

  • Yes I tried it on two different launchPads but result is same. Maybe this problem is caused by header files? Though header files are the original header files that come when I install the tiva driver. I haven't made any changes on them.

    So if we turn back to the ohm ninja code, there comes errorFlag 1 from the following part of code for some reason.

    // CAN interrupt handler
    void CANIntHandler(void) {

    unsigned long status = CANIntStatus(CAN1_BASE, CAN_INT_STS_CAUSE); // read interrupt status

    if(status == CAN_INT_INTID_STATUS) { // controller status interrupt
    status = CANStatusGet(CAN1_BASE, CAN_STS_CONTROL); // read back error bits, do something with them?
    errFlag = 1;
    } else if(status == 1) { // message object 1
    CANIntClear(CAN1_BASE, 1); // clear interrupt
    errFlag = 0; // clear any error flags
    } else { // should never happen
    UARTprintf("Unexpected CAN bus interrupt\n");
    }
    }

    --------------------------------------------------------------------------------------------------------------------------

    Do you have any idea about it?

  • I will forward your question to our CAN expert for comments. 

  • Thank you Charles. I look forward to your and the experts comments.

  • When using CAN1 on the EK-TM4C1294X Launchpad, you need to disable TARGET_VBUS. The schematics are in the User's Guide. PB1 is connected to the signal TARGET_VBUS, which is tied to 5V when the switch U4 is enabled. You need to configure PD6 high, either as an output high or by adding a pullup resistor.

  • If you have not already done so, you may want to look at this application note and examples.

    www.ti.com/.../spna245.pdf

  • Hello Bob,

    I configured PD6 output high with adding this code:

    // set PD6 output high
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_6);
    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, GPIO_PIN_6);

    ---------------------------------------------------------------------------------------------------

    But nothing changes.Still errorFlag is 1. Is there anything wrong with this code?

    Following pic is the output from PA1 (  "GPIOPinConfigure(GPIO_PA1_U0TX) " )

    And this pic is the output from PB1: (  "GPIOPinConfigure(GPIO_PB1_CAN1TX) ")

    As you see PA1's UART message is about 3.3V but PB1's output is constant 5V.

    And also do you have any idea about why error flag is still 1?