Tool/software: TI-RTOS
I am using a TM4C1294NCPDT, CCS 6.1.2, TIRTOS 2.16.0.08 and compiler 5.2.7.
I looked at a couple of examples on writing a CAN driver but my driver is not yet working for send or receive of CAN any data.
The CPU I am using has CAN hooked up to CPU pins PB0 (CAN RX) and PB1 (CAN TX). I configure object number (CAN mailbox) 1 for receive with a wide open filter / mask and I use object number 2, 3, and 4 to transmit for testing the code.
Anyway, here is my code.
Globals:
typedef struct
{
bool busy;
bool CAN_Configured;
unsigned long g_ulMsg1Count, g_ulMsg2Count, g_ulMsg3Count, g_bMsgObj3Sent;
tCANMsgObject sMsgObjectRx;
tCANMsgObject sMsgObjectTx;
bool g_bErrFlag;
uint8_t message[MESSAGE_LENGTH]; // buffer for data
} CAN_MANAGER;
static CAN_MANAGER CAN_Manager = {0,0,0,0,0,0,0,0,0};
tCANMsgObject testTx;
#define CAN_MSG_OBJ_RX 1
The main loop, init can and send a message over and over.
int main(void){ // >>>>>>>>>>Disable wdog to debug this or wdog will TMO on a break point and reset the board.
Board_initGeneral();
CAN_init();
while(1)
{
sendTestCAN_Message();
SMALL_DELAY;
}
How the CAN init is done.
void CAN_init(void)
{
Hwi_Handle myHwi;
Error_Block eb;
Hwi_Params hwiParams;
memset((void*)&CAN_Manager, 0x00, sizeof(CAN_Manager));
SysCtlPeripheralEnable(GPIO_PORTB_BASE);
SMALL_DELAY; // when SysCtlPeripheralEnable() is called, a small delay is needed before the device can be used.
GPIOPinConfigure(GPIO_PB0_CAN1RX); // CAN RX is PB0
GPIOPinConfigure(GPIO_PB1_CAN1TX); // CAN TX is PB1
GPIOPinTypeCAN(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0);
CANInit(CAN0_BASE);
CANBitRateSet(CAN0_BASE, 120000000, 500000);
printf("CAN 0 init\n");
//CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 500000);
printf ("CAN 0 clock set\n");
CANEnable(CAN0_BASE);
printf ("CAN 0 enabled\n");
//p81/706 Periph Driver Lib spmu298a.pdf Enable CAN Interrupts (all three IRQ's)
CANIntEnable (CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
printf ("CAN 0 ints enabled\n");
// Configure a receive object.
CAN_Manager.sMsgObjectRx.ui32MsgID = (0x602);
CAN_Manager.sMsgObjectRx.ui32MsgIDMask = 0; // filter mask. 0=accept all e2e.ti.com/.../568684
CAN_Manager.sMsgObjectRx.ui32Flags = MSG_OBJ_RX_INT_ENABLE | MSG_OBJ_USE_ID_FILTER; // enable interrupt on RX
CAN_Manager.sMsgObjectRx.ui32MsgLen = 8; // allow up to 8 bytes
CANMessageSet(CAN0_BASE, 1, &CAN_Manager.sMsgObjectRx, MSG_OBJ_TYPE_RX);
/* Install the IRQ now*/
Error_init(&eb);
Hwi_Params_init(&hwiParams);
myHwi = Hwi_create(INT_CAN0_TM4C129, CANIntHandler, &hwiParams, &eb); // see tivaware\inc\hw_ints.h
if(NULL == myHwi)
{
LOG_EVENT(ERROR_CIB_APP_BOARD_ERROR, "Error installing IRQ for CAN0");
}
//IntEnable(INT_CAN0); //Enable CAN interrupt
//CANEnable(CAN0_BASE); //Enable CAN for operation
CAN_Manager.CAN_Configured = TRUE;
} // end can_init()
Send a message, called from main in a loop after init.
void sendTestCAN_Message(void)
{
if(CAN_Manager.CAN_Configured ==0)
{
printf("CAN not configured, return from send CAN message\n");
return;
}
CAN_Manager.sMsgObjectTx.ui32MsgID = 0x7A7;
CAN_Manager.sMsgObjectTx.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
CAN_Manager.sMsgObjectTx.ui32MsgLen = 8;
CAN_Manager.sMsgObjectTx.pui8MsgData = CAN_Manager.message; // ptr to TX message content
CANMessageSet(CAN0_BASE, 2, &CAN_Manager.sMsgObjectTx, MSG_OBJ_TYPE_TX); // send the message out mbx 2
CANMessageSet(CAN0_BASE, 3, &CAN_Manager.sMsgObjectTx, MSG_OBJ_TYPE_TX); // send the message out mbx 3
CANMessageSet(CAN0_BASE, 4, &CAN_Manager.sMsgObjectTx, MSG_OBJ_TYPE_TX); // send the message out mbx 4
testTx.ui32MsgID = 0x7A7;
testTx.ui32Flags = MSG_OBJ_TX_INT_ENABLE;
testTx.ui32MsgLen = 8;
testTx.pui8MsgData = CAN_Manager.message; // ptr to TX message content
CANMessageSet(CAN0_BASE, 2, &testTx, MSG_OBJ_TYPE_TX); // send the message
printf("CAN TX\n");
}
The IRQ handler, note this never gets called.
void CANIntHandler(UArg arg)
{
unsigned long ulStatus;
//
// 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)
{
//
// 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.
//
ulStatus = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL); // CAN_STS_NEWDAT
//
// Set a flag to indicate some errors may have occurred.
//
CAN_Manager.g_bErrFlag = 1;
return; // do we want to return here?
}
if(ulStatus == 1) //If msg object is 1, message received CAN obj 1
{
CANIntClear(CAN0_BASE, 1);
CAN_Manager.g_ulMsg1Count++;
CAN_Manager.g_bErrFlag = 0;
}
else if(ulStatus == 2) //If msg object is 2, message received CAN obj 2
{
CANIntClear(CAN0_BASE, 2);
CAN_Manager.g_ulMsg2Count++;
CAN_Manager.g_bErrFlag = 0;
}
else if(ulStatus == 3)
{
CANIntClear(CAN0_BASE, 3);
CAN_Manager.g_ulMsg3Count++;
CAN_Manager.g_bMsgObj3Sent = 1;
CAN_Manager.g_bErrFlag = 0;
}
else if(ulStatus == 8)
{
CANIntClear(CAN0_BASE, 8);
CAN_Manager.g_ulMsg3Count++;
CAN_Manager.g_bMsgObj3Sent = 1;
CAN_Manager.g_bErrFlag = 0;
}
else if(ulStatus == 16)
{
CANIntClear(CAN0_BASE, 16);
CAN_Manager.g_ulMsg3Count++;
CAN_Manager.g_bMsgObj3Sent = 1;
CAN_Manager.g_bErrFlag = 0;
}
//
// Otherwise, something unexpected caused the interrupt. This should
// never happen.
//
else
{
//
// Spurious interrupt handling can go here.
//
}
}
I probably missed something simple but I have not found it yet.
Thanks,
Doug