Part Number: EK-TM4C129EXL
Tool/software: Code Composer Studio
Hi, I am developing a CAN based communication system whereby I will need to transmit CAN messeges to multiple nodes. As a start, I have attempted my setup using 2 Nodes (2 TM4C129EXL launchpads) and this seems to work as expected although I have a some minor issues in filtering the message ID which is not related to this issue (refer to : e2e.ti.com/.../641798).
However when I attempted to communicate with PCAN-USB Adapter (Transmit from launchpad and receive from PCAN-USB adapter), there seems to be some error messages. The transmit will stop after a single transmit. I am using PCAN-View to trace the received messages.
I am still trying to figure out what is causing this errors. Attached the schematics, terminal output and error messages.
Simple Schematics:
Hardware setup:
PCAN-USB setup:
Error message:
Terminal output at transmit side:
//*****************************************************************************
//
// multi_tx.c - Peripheral example demonstrating multiple CAN message
// transmission.
//
// Copyright (c) 2010-2017 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.1.4.178 of the Tiva Firmware Development Package.
//
//*****************************************************************************
#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>Multiple CAN TX (multi_tx)</h1>
//!
//! This example shows how to set up the CAN to send multiple messages. The
//! CAN peripheral is configured to send messages with 4 different CAN IDs.
//! Two of the messages (with different CAN IDs) are sent using a shared
//! message object. This shows how to reuse a message object for multiple
//! messages. The other two messages are sent using their own message objects.
//! All four messages are transmitted once per second. The content of each
//! message is a test 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 B peripheral (for CAN0 pins)
//! - CAN0RX - PB4
//! - CAN0TX - PB5
//!
//! The following UART signals are configured only for displaying console
//! messages for this example. These are not required for operation of CAN.
//! - GPIO port A peripheral (for UART0 pins)
//! - UART0RX - PA0
//! - UART0TX - 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_ui32IntCount = 0;
//*****************************************************************************
//
// Counters that are used to count the number of messages on each of the
// three message objects that are used in this example.
//
//*****************************************************************************
volatile uint32_t g_ui32Msg1Count = 0;
volatile uint32_t g_ui32Msg2Count = 0;
volatile uint32_t g_ui32Msg3Count = 0;
volatile uint32_t g_ui32Msg4Count = 0;
//*****************************************************************************
//
// A flag to indicate that CAN controller message object 3 has sent a message.
//
//*****************************************************************************
volatile bool g_bMsgObj3Sent = 0;
//*****************************************************************************
//
// A flag to indicate that some transmission error occurred.
//
//*****************************************************************************
volatile bool g_bErrFlag = 0;
//*****************************************************************************
//
// CAN message objects that will hold the separate CAN messages. These could
// also be allocated on the stack but be careful because these structures
// each take about 20 bytes.
//
//*****************************************************************************
tCANMsgObject g_sCANMsgObject1;
tCANMsgObject g_sCANMsgObject2;
tCANMsgObject g_sCANMsgObject3;
tCANMsgObject g_sCANMsgObject4;
//*****************************************************************************
//
// Message buffers that hold the contents of the 4 different messages that
// are being transmitted. Each one is a different length.
//
//*****************************************************************************
uint8_t g_pui8Msg1[4] = { 0, 0, 0, 0 };
uint8_t g_pui8Msg2[5] = { 2, 2, 2, 2, 2 };
uint8_t g_pui8Msg3[6] = { 3, 3, 3, 3, 3, 3 };
uint8_t g_pui8Msg4[8] = { 4, 4, 4, 4, 5, 5, 5, 5 };
uint8_t g_pui8Msg_t[4] = { 10, 15, 3, 2 };
//*****************************************************************************
//
// This function sets up UART0 to be used for a console to display information
// as the example is running.
//
//*****************************************************************************
void
InitConsole(void)
{
//PD4/PD5
// Enable GPIO port A which is used for UART0 pins.
// TODO: change this to whichever GPIO port you are using.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
//
// Configure the pin muxing for UART0 functions on port A0 and A1.
// This step is not necessary if your part does not support pin muxing.
// TODO: change this to select the port/pin you are using.
//
GPIOPinConfigure(GPIO_PD4_U2RX);
GPIOPinConfigure(GPIO_PD5_U2TX);
//
// Enable UART0 so that we can configure the clock.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART2);
//
// Use the internal 16MHz oscillator as the UART clock source.
//
UARTClockSourceSet(UART2_BASE, UART_CLOCK_PIOSC);
//
// Select the alternate (UART) function for these pins.
// TODO: change this to select the port/pin you are using.
//
GPIOPinTypeUART(GPIO_PORTD_BASE, GPIO_PIN_4 | GPIO_PIN_5);
//
// Initialize the UART for console I/O.
//
UARTStdioConfig(2, 115200, 16000000);
}
//*****************************************************************************
//
// This function prints some information about the CAN message to the
// serial port for information purposes only.
//
//*****************************************************************************
void
PrintCANMessageInfo(tCANMsgObject *psCANMsg, uint32_t ui32MsgObj)
{
unsigned int uIdx;
UARTprintf("Sending msg: obj=%d ID=0x%04X msg=0x", ui32MsgObj,
psCANMsg->ui32MsgID);
for(uIdx = 0; uIdx < psCANMsg->ui32MsgLen; uIdx++)
{
UARTprintf("%02X ", psCANMsg->pui8MsgData[uIdx]);
}
UARTprintf("\n");
}
//*****************************************************************************
//
// 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 is used for sending
// message 1.
//
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_ui32Msg1Count++;
//
// Since the message was sent, clear any error flags.
//
g_bErrFlag = 0;
}
//
// Check if the cause is message object 2, which is used for sending
// message 2.
//
else if(ui32Status == 2)
{
//
// Getting to this point means that the TX interrupt occurred on
// message object 2, and the message TX is complete. Clear the
// message object interrupt.
//
CANIntClear(CAN0_BASE, 2);
//
// 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_ui32Msg2Count++;
//
// Since the message was sent, clear any error flags.
//
g_bErrFlag = 0;
}
//
// Check if the cause is message object 3, which is used for sending
// messages 3 and 4.
//
else if(ui32Status == 3)
{
//
// Getting to this point means that the TX interrupt occurred on
// message object 3, and a message TX is complete. Clear the
// message object interrupt.
//
CANIntClear(CAN0_BASE, 3);
//
// 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_ui32Msg3Count++;
//
// Set the flag indicating that a message was sent using message
// object 3. The program main loop uses this to know when to send
// another message using message object 3.
//
g_bMsgObj3Sent = 1;
//
// Since the message was sent, clear any error flags.
//
g_bErrFlag = 0;
}
else if(ui32Status == 4)
{
//
// Getting to this point means that the TX interrupt occurred on
// message object 3, and a message TX is complete. Clear the
// message object interrupt.
//
CANIntClear(CAN0_BASE, 4);
//
// 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_ui32Msg4Count++;
//
// 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
//
// 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)
ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
SYSCTL_OSC_MAIN |
SYSCTL_USE_OSC)
,25000000);
#else
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHZ);
#endif
//
// Set up the serial console to use for displaying messages. This is
// just for this example program and is not needed for CAN operation.
//
InitConsole();
UARTprintf("Debug: check console\n");
//
// For this example CAN0 is used with RX and TX pins on port B4 and B5.
// 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.
//
//
// Initialize message object 1 to be able to send CAN message 1. This
// message object is not shared so it only needs to be initialized one
// time, and can be used for repeatedly sending the same message ID.
//
g_sCANMsgObject1.ui32MsgID = 0x1001;
g_sCANMsgObject1.ui32MsgIDMask = 0;
g_sCANMsgObject1.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
g_sCANMsgObject1.ui32MsgLen = sizeof(g_pui8Msg1);
g_sCANMsgObject1.pui8MsgData = g_pui8Msg1;
//
// Initialize message object 2 to be able to send CAN message 2. This
// message object is not shared so it only needs to be initialized one
// time, and can be used for repeatedly sending the same message ID.
//
g_sCANMsgObject2.ui32MsgID = 0x2001;
g_sCANMsgObject2.ui32MsgIDMask = 0;
g_sCANMsgObject2.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
g_sCANMsgObject2.ui32MsgLen = sizeof(g_pui8Msg2);
g_sCANMsgObject2.pui8MsgData = g_pui8Msg2;
// using obj 4
g_sCANMsgObject4.ui32MsgID = 0x4001;
g_sCANMsgObject4.ui32MsgIDMask = 0;
g_sCANMsgObject4.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
g_sCANMsgObject4.ui32MsgLen = sizeof(g_pui8Msg_t);
g_sCANMsgObject4.pui8MsgData = g_pui8Msg_t;
//
// Enter loop to send messages. Four messages will be sent once per
// second. The contents of each message will be changed each time.
//
for(;;)
{
//
// Send message 1 using CAN controller message object 1. This is
// the only message sent using this message object. The
// CANMessageSet() function will cause the message to be sent right
// away.
//
PrintCANMessageInfo(&g_sCANMsgObject1, 1);
CANMessageSet(CAN0_BASE, 1, &g_sCANMsgObject1, MSG_OBJ_TYPE_TX);
//
// Send message 2 using CAN controller message object 2. This is
// the only message sent using this message object. The
// CANMessageSet() function will cause the message to be sent right
// away.
//
PrintCANMessageInfo(&g_sCANMsgObject2, 2);
CANMessageSet(CAN0_BASE, 2, &g_sCANMsgObject2, MSG_OBJ_TYPE_TX);
//
// Load message object 3 with message 3. This is needs to be done each
// time because message object 3 is being shared for two different
// messages.
//
g_sCANMsgObject3.ui32MsgID = 0x3001;
g_sCANMsgObject3.ui32MsgIDMask = 0;
g_sCANMsgObject3.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
g_sCANMsgObject3.ui32MsgLen = sizeof(g_pui8Msg3);
g_sCANMsgObject3.pui8MsgData = g_pui8Msg3;
//
// Clear the flag that indicates that message 3 has been sent. This
// flag will be set in the interrupt handler when a message has been
// sent using message object 3.
//
g_bMsgObj3Sent = 0;
//
// Now send message 3 using CAN controller message object 3. This is
// the first message sent using this message object. The
// CANMessageSet() function will cause the message to be sent right
// away.
//
PrintCANMessageInfo(&g_sCANMsgObject3, 3);
CANMessageSet(CAN0_BASE, 3, &g_sCANMsgObject3, MSG_OBJ_TYPE_TX);
//
// Wait for the indication from the interrupt handler that message
// object 3 is done, because we are re-using it for another message.
//
while(!g_bMsgObj3Sent)
{
SimpleDelay();
}
//
// Load message object 3 with message 4. This is needed because
// message object 3 is being shared for two different messages.
//
g_sCANMsgObject3.ui32MsgID = 0x3002;
g_sCANMsgObject3.ui32MsgIDMask = 0;
g_sCANMsgObject3.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
g_sCANMsgObject3.ui32MsgLen = sizeof(g_pui8Msg4);
g_sCANMsgObject3.pui8MsgData = g_pui8Msg4;
//
// Now send message 4 using CAN controller message object 3. This is
// the second message sent using this message object. The
// CANMessageSet() function will cause the message to be sent right
// away.
//
PrintCANMessageInfo(&g_sCANMsgObject3, 3);
CANMessageSet(CAN0_BASE, 3, &g_sCANMsgObject3, MSG_OBJ_TYPE_TX);
PrintCANMessageInfo(&g_sCANMsgObject4, 4);
CANMessageSet(CAN0_BASE, 4, &g_sCANMsgObject4, MSG_OBJ_TYPE_TX);
//
// Wait 1 second before continuing
//
SimpleDelay();
//
// Check the error flag to see if errors occurred
//
if(g_bErrFlag)
{
UARTprintf(" error - cable connected?\n");
}
else
{
//
// If no errors then print the count of message sent
//
UARTprintf(" total count = %u\n",
g_ui32Msg1Count + g_ui32Msg2Count + g_ui32Msg3Count + g_ui32Msg4Count );
}
//
// Change the value in the message data for each of the messages.
//
(*(uint32_t *)g_pui8Msg1)++;
(*(uint32_t *)g_pui8Msg2)++;
(*(uint32_t *)g_pui8Msg3)++;
(*(uint32_t *)&g_pui8Msg4[0])++;
(*(uint32_t *)&g_pui8Msg4[4])--;
(*(uint32_t *)g_pui8Msg_t)++;
}
//
// Return no errors
//
return(0);
}

