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);
}