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.

TM4C1294 CAN loopback test

Other Parts Discussed in Thread: SN65HVD233

Hi

I am new to tm4c microcontroller but I read many discussion about CAN interface like discussion (e2e.ti.com/.../211785) . I’m trying to test CAN loopback mode in my customized board based on tm4c1294 and SN65HVD233 CAN transceiver with two parallel 120-ohm termination across CANH/CANL.

1) when I set “HWREG(CAN0_BASE+CAN0_O_CTL) |= CAN_CTL_TEST” and “HWREG(CAN0_BASE+CAN0_O_TST) |= CAN_TST_LBACK” for testing internal loopback mode, 4 bytes data were transmitted correctly but received just 3bytes and one message was lost(sCANMessageRX.ui32Flags = MSG_OBJ_DATA_LOST). 

2)In order to testing loopback of SN65HVD233 I set LBK pin(5) to ‘1’ so I don't use internal loopback. there is same data on scope shots of R & D pins .According to my CANIntHandler() result, the cause of interrupt is a controller status interrupt (ui32Status = CAN_INT_INTID_STATUS) and when reading the status register, its value equals to 0x08(CAN_STATUS_TXOK) which according to ti CAN simple_tx example it refers to accruing an error.

below is my code in internal loopback test.

External loopback code is same  as below but I don't set internal loopback register and set LBK pin to '1'. also I checked common mistakes like two parallel 120-ohm termination across CANH/CANL and etc.

any help would be greatly appreciated.

N. B.

#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"
#include <stdio.h>
#include <string.h>
#include "inc/hw_types.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/uart.h"
#include "driverlib/can.h"

#define LED1_PERIPH	SYSCTL_PERIPH_GPIOM
#define LED1_PORT	GPIO_PORTM_BASE
#define LED1_PIN	GPIO_PIN_4

#define CAN1_PERIPH	SYSCTL_PERIPH_GPIOB
#define CAN1_PORT	GPIO_PORTB_BASE
#define CAN1_RX_PIN	GPIO_PIN_0
#define CAN1_TX_PIN	GPIO_PIN_1

void UART4Init(void);
void CANIntHandler(void);
void UARTStringPut(uint32_t uart_channel,char *string_ptr);
void SimpleDelay(void);
//*****************************************************************************
volatile uint32_t g_ui32MsgCount = 0;

volatile unsigned long rx_ulMsgCount = 0;
volatile unsigned long rx_bRXFlag = 0;
volatile unsigned long rx_bErrFlag = 0;
volatile unsigned long g_ulMsgCount = 0;

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

#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

int
main(void)
{
	// Run from the PLL at 120 MHz.
	g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
			SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
			SYSCTL_CFG_VCO_480), 120000000);

	tCANMsgObject sCANMessageTX;
	tCANMsgObject sCANMessageRX;
	uint32_t ui32MsgData,CLOCK1,CLOCK2;
	uint8_t *pui8MsgData;
	uint8_t s[20];
	uint8_t s1[20];
	uint8_t s2[20];
	uint8_t s3[20];
	unsigned char ucMsgData[4];
	unsigned char rMsgData[4];
	uint32_t i = 0,c = 0,temp = 0,x = 0,uIdx = 0;

	pui8MsgData = (uint8_t *)&ui32MsgData;

	// Configure LED Pins
	SysCtlPeripheralEnable(LED1_PERIPH);
	GPIOPinTypeGPIOOutput(LED1_PORT, LED1_PIN);

	// Set up the serial console to use for displaying messages.  This is
	// just for this example program and is not needed for CAN operation.
	//
	UART4Init();

	// For this example CAN1 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.
	//
	SysCtlPeripheralEnable(CAN1_PERIPH);

	//
	// Configure the GPIO pin muxing to select CAN1 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.
	//
	GPIOPinConfigure(GPIO_PB0_CAN1RX);
	GPIOPinConfigure(GPIO_PB1_CAN1TX);

	//
	// 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.
	//
	GPIOPinTypeCAN(CAN1_PORT, CAN1_RX_PIN | CAN1_TX_PIN);

	//
	// The GPIO port and pins have been set up for CAN.  The CAN peripheral
	// must be enabled.
	//
	SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN1);
	//
	// Initialize the CAN controller
	//
	CANInit(CAN1_BASE);

	// Set up the bit rate for the CAN bus.
	//
	CLOCK1=SysCtlClockGet();
	CLOCK2=g_ui32SysClock;

	CANBitRateSet(CAN1_BASE, g_ui32SysClock, 10000);


	//
	// Enable interrupts on the CAN peripheral.
	CANIntEnable(CAN1_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);

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

	// Loopback Register
	HWREG(CAN1_BASE+CAN_O_CTL) |= CAN_CTL_TEST;
	HWREG(CAN1_BASE+CAN_O_TST) |= CAN_TST_LBACK;

	//
	// Enable the CAN for operation.
	//
	CANEnable(CAN1_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.
	//
	*(unsigned long *)ucMsgData = 0;
	sCANMessageTX.ui32MsgID = 1;
	sCANMessageTX.ui32MsgIDMask = 0;
	sCANMessageTX.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
	sCANMessageTX.ui32MsgLen = sizeof(ucMsgData);
	sCANMessageTX.pui8MsgData = ucMsgData;

	CANMessageSet(CAN1_BASE, 1, &sCANMessageTX, MSG_OBJ_TYPE_TX);

	sCANMessageRX.ui32MsgID = 0;
	sCANMessageRX.ui32MsgIDMask = 0;
	sCANMessageRX.ui32Flags =  MSG_OBJ_USE_ID_FILTER| MSG_OBJ_FIFO;
	sCANMessageRX.ui32MsgLen = 8;

	CANMessageSet(CAN1_BASE, 1, &sCANMessageRX, MSG_OBJ_TYPE_RX);
	CANMessageSet(CAN1_BASE, 2, &sCANMessageRX, MSG_OBJ_TYPE_RX);
	CANMessageSet(CAN1_BASE, 3, &sCANMessageRX, MSG_OBJ_TYPE_RX);


	sCANMessageRX.ui32Flags = MSG_OBJ_USE_ID_FILTER;
	CANMessageSet(CAN1_BASE, 4, &sCANMessageRX, MSG_OBJ_TYPE_RX);
	//
	// 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.
	//
	for(;;)
	{
		c++;
		// blinker
		if (c<10)
			GPIOPinWrite(LED1_PORT, LED1_PIN, LED1_PIN);


		else if (c>10)
			GPIOPinWrite(LED1_PORT, LED1_PIN, 0);

		if (c==20)
			c=0;

		// 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.

		//
		SimpleDelay();
		CANMessageSet(CAN1_BASE, 1, &sCANMessageTX, MSG_OBJ_TYPE_TX);

		// Check the error flag to see if errors occurred
		//
		if(g_bErrFlag==1)
		{
			sCANMessageRX.pui8MsgData = rMsgData;
			CANMessageGet(CAN1_BASE,4, &sCANMessageRX, 0);

			// Clear the pending message flag so that the interrupt handler can
			// set it again when the next message arrives.
			rx_bRXFlag = 0;

			// Check to see if there is an indication that some messages were
			// lost.
			if(sCANMessageRX.ui32Flags & MSG_OBJ_DATA_LOST)
			{
				sprintf(s2,"CAN message loss detected\n");
				UARTStringPut(UART4_BASE,s2);
			}

			sprintf(s,"error - cable connected?\r");
			UARTStringPut(UART4_BASE,s);
			break;
		}
		else if(g_bErrFlag==2)
		{
			x++;
			// If no errors then print the count of message sent
			sprintf(s1,"total count = %u\r", g_ui32MsgCount);
			UARTStringPut(UART4_BASE,s1);

			if( temp < 4)
			{
				ucMsgData[temp]+=(5*g_ui32MsgCount);
				temp++;

				if(temp >= 4)
				{
					temp = 0;
					SimpleDelay();
					sprintf(s, "Data: %02X %02X %02X %02X %02X\r", ucMsgData[0], ucMsgData[1], ucMsgData[2], ucMsgData[3],x);
					UARTStringPut(UART4_BASE,s);
					break;
				}
			}
		}
	}
	// RX
	for(;;)
	{
		// If the flag is set, that means that the RX interrupt occurred and
		// there is a message ready to be read from the CAN
		if(rx_bRXFlag==1)
		{
			// Reuse the same message object that was used earlier to configure
			// the CAN for receiving messages.  A buffer for storing the
			// received data must also be provided, so set the buffer pointer
			// within the message object.
			sCANMessageRX.pui8MsgData = rMsgData;


			// Read the message from the CAN.  Message object number 1 is used
			// (which is not the same thing as CAN ID).  The interrupt clearing
			// flag is not set because this interrupt was already cleared in
			// the interrupt handler.
			CANMessageGet(CAN1_BASE,3, &sCANMessageRX, 0);

			// Clear the pending message flag so that the interrupt handler can
			// set it again when the next message arrives.
			rx_bRXFlag = 0;

			// Check to see if there is an indication that some messages were
			// lost.
			if(sCANMessageRX.ui32Flags & MSG_OBJ_DATA_LOST)
			{
				sprintf(s2,"CAN message loss detected\n");
				UARTStringPut(UART4_BASE,s2);
			}

			sprintf(s3, "Data received: %02X %02X %02X %02X\r", rMsgData[0], rMsgData[1], rMsgData[2], rMsgData[3]);
			UARTStringPut(UART4_BASE,s3);

			break;
		}
	}
}
void UARTStringPut(uint32_t uart_channel,char *string_ptr)
{
	while(*string_ptr)
		UARTCharPut(uart_channel, *string_ptr++);
}



//*****************************************************************************
//
// This function sets up UART4 to be used for a console to display information
// as the example is running.
//
//*****************************************************************************
void UART4Init(void)
{
	//
	// Enable the GPIO Peripheral used by the UART.
	//
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART4);
	while(!(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_UART4)));//It takes 5 System Clock Cycles after which the peripheral will be addressable.
	//
	// Enable UART4
	//
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	while(!(ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA)));//It takes 5 System Clock Cycles after which the peripheral will be addressable.

	//
	// Configure GPIO Pins for UART mode.
	//
	ROM_GPIOPinConfigure(GPIO_PA2_U4RX);
	ROM_GPIOPinConfigure(GPIO_PA3_U4TX);
	ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_2 | GPIO_PIN_3);

	ROM_UARTConfigSetExpClk(UART4_BASE, g_ui32SysClock, 115200,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |UART_CONFIG_PAR_NONE));
	ROM_UARTEnable(UART4_BASE);

}
//*****************************************************************************
//
// 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(CAN1_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(CAN1_BASE, CAN_STS_CONTROL);

		//
		// Set a flag to indicate some errors may have occurred.
		//
		g_bErrFlag = 1;
		rx_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(CAN1_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 = 2;
		rx_bErrFlag = 2;

		rx_bRXFlag = 1;
		rx_ulMsgCount++;


	}
}
void
SimpleDelay(void)
{
	//
	// Delay cycles for 1 second
	//
	SysCtlDelay(16000000 / 3);
}