FlexCAN usage example
Since we included our iMX FlexCAN driver in the iMX25 Topaz image binaries we have received a couple of requests for sample code, so here it is:
#include "FlexCANSDK.h"
#define CAN_BITRATE (125*1000) // 125 kHz
#define CAN_READ_INTERVAL 1000 // Set to INFINITE to wait forever for a CAN Frame
#define CAN_WRITE_INTERVAL 500
CRITICAL_SECTION gCS;
LPCWSTR DataToHexString(const PCAN_FRAME pCANFrame)
{
static WCHAR szHexString[100];
WCHAR szHexByte[7];
EnterCriticalSection(&gCS);
{
szHexString[0] = 0;
if (pCANFrame->btDataLen)
{
wsprintf(szHexByte, L"0x%02X", pCANFrame->btData[0]);
wcscat_s(szHexString, _countof(szHexString), szHexByte);
for (int i=1; i<pCANFrame->btDataLen; i++)
{
wsprintf(szHexByte, L", 0x%02X", pCANFrame->btData[i]);
wcscat_s(szHexString, _countof(szHexString), szHexByte);
}
}
} LeaveCriticalSection(&gCS);
return szHexString;
}
DWORD WINAPI CANReadThread(LPVOID lpParameter)
{
HANDLE hFinishEvent = (HANDLE)lpParameter;
CAN_FRAME canFrame = {0};
canFrame.bExtended = CAN_EXTENDED; // Receive any extended frame
LOGMSG(ZONE_INFO, L"CAN Read Thread initialized; waiting for %s CAN frames...\r\n", (CAN_EXTENDED == canFrame.bExtended) ? L"Extended" : L"Standard");
do
{
if (ERROR_SUCCESS == FlexCANReadFrame(1, &canFrame, CAN_READ_INTERVAL, 0))
{ // Convert data to string, copy the string and show received frame
LPWSTR pszData = wcsdup(DataToHexString(&canFrame));
if (canFrame.bExtended == CAN_EXTENDED)
LOGMSG(ZONE_INFO, L"Read CAN frame with ID 0x%08X, Data: %s\r\n", canFrame.ui32ID, pszData);
else
LOGMSG(ZONE_INFO, L"Read CAN frame with ID 0x%03X, Data: %s\r\n", canFrame.ui32ID, pszData);
// Clean up
free(pszData);
}
} while (WAIT_TIMEOUT == WaitForSingleObject(hFinishEvent, 0));
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
// Register with debug subsystem
RETAILREGISTERZONES(NULL);
InitializeCriticalSection(&gCS);
HANDLE hFinishEvent = NULL;
HANDLE hReadThread = NULL;
for (;;)
{ // Use loop for easy break-out error handling
if (!FlexCANInit(1))
break;
DWORD dwBitrate = CAN_BITRATE;
if (!FlexCANSetBitrate(1, &dwBitrate))
break;
LOGMSG(ZONE_INFO, L"Bitrate set to %d (requested %d)\r\n", dwBitrate, CAN_BITRATE);
hFinishEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!hFinishEvent)
break;
// Create the read thread that will receive all CAN Frames
hReadThread = CreateThread(NULL, 0, CANReadThread, (LPVOID)hFinishEvent, 0, NULL);
if (!hReadThread)
break;
// Some time to see CAN Frames coming in
Sleep(10000);
CAN_FRAME canFrame = {0};
for (int i=0; i<10; i++)
{ // Send a couple of frames at highest priority (0)
canFrame.bExtended = CAN_EXTENDED;
canFrame.btData[0] = 0x10;
canFrame.btData[1] = 0x11;
canFrame.btData[2] = 0x12;
canFrame.btDataLen = 3;
canFrame.ui32ID = 0x12345678;
DWORD dwRet = FlexCANWriteFrame(1, CAN_DATA, CAN_TXNOW, 0, &canFrame, 500);
LOGMSG(ZONE_INFO, L"Frame with ID 0x%08X and data %s sent. Result: %d\r\n", canFrame.ui32ID, DataToHexString(&canFrame), dwRet);
Sleep(CAN_WRITE_INTERVAL);
}
// Signal read thread to finish
SetEvent(hFinishEvent);
if (WAIT_OBJECT_0 != WaitForSingleObject(hReadThread, CAN_READ_INTERVAL*2))
TerminateThread(hReadThread, 0);
// And wait for a frame with ID 0x12345678 for 10 seconds (no other CAN frames are accepted during this time)
canFrame.bExtended = CAN_EXTENDED;
canFrame.ui32ID = 0x12345678;
LOGMSG(ZONE_INFO, L"Waiting for extended frame with ID 0x%08X...\r\n", canFrame.ui32ID);
DWORD dwRet = FlexCANReadFrame(1, &canFrame, 10000, 0x1FFFFFFF);
LOGMSG(ZONE_INFO, L"Specific FlexCANReadFrame result: %d\r\n", dwRet);
if (ERROR_SUCCESS == dwRet)
LOGMSG(ZONE_INFO, L"Read CAN frame with ID 0x%08X, Data: %s\r\n", canFrame.ui32ID, DataToHexString(&canFrame));
// Now read any frame (ui32IDMask set to 0)
LOGMSG(ZONE_INFO, L"Waiting for extended frame with any ID...\r\n");
dwRet = FlexCANReadFrame(1, &canFrame, 10000, 0);
LOGMSG(ZONE_INFO, L"Unspecific FlexCANReadFrame result: %d\r\n", dwRet);
if (ERROR_SUCCESS == dwRet)
{ // Show received frame
if (canFrame.bExtended == CAN_EXTENDED)
LOGMSG(ZONE_INFO, L"Read CAN frame with ID 0x%08X, Data: %s\r\n", canFrame.ui32ID, DataToHexString(&canFrame));
else
LOGMSG(ZONE_INFO, L"Read CAN frame with ID 0x%03X, Data: %s\r\n", canFrame.ui32ID, DataToHexString(&canFrame));
}
// Now transfer a whole bunch of messages in one go
CAN_TRANSFER_BLOCK canBlock;
canBlock.dwNumPackets = 32;
canBlock.pCANPackets = new CAN_PACKET[canBlock.dwNumPackets];
if (canBlock.pCANPackets)
{
for (DWORD i=0; i<canBlock.dwNumPackets; i++)
{ // Init packets; data from max to 0
canBlock.pCANPackets[i].bRemote = CAN_DATA; // Data frame
canBlock.pCANPackets[i].btIndex = 0xFF; // Let driver find a free message buffer
canBlock.pCANPackets[i].btPriority = 0; // Highest priority
canBlock.pCANPackets[i].bTxOnRemoteRx = CAN_TXNOW; // Transfer immediately
canBlock.pCANPackets[i].bWrite = CAN_WRITE; // We want to write this frame
canBlock.pCANPackets[i].canFrame.bExtended = CAN_STANDARD; // Standard address (11 bit)
canBlock.pCANPackets[i].canFrame.btData[0] = (BYTE)(0xFF - (i*(256/canBlock.dwNumPackets)));
canBlock.pCANPackets[i].canFrame.btDataLen = 1; // 1 byte data
canBlock.pCANPackets[i].canFrame.ui32ID = 0x123; // Address
canBlock.pCANPackets[i].dwTimeout = 100; // Write timeout
}
BOOL bRet = FlexCANTransfer(1, &canBlock);
LOGMSG(ZONE_INFO, L"FlexCANTransfer result: %s\r\n", bRet ? L"TRUE" : L"FALSE");
for (DWORD i=0; i<canBlock.dwNumPackets; i++)
LOGMSG(ZONE_INFO, L"Individual transmit %d transmit result: %d\r\n", i, canBlock.pCANPackets[i].dwError);
}
// Now write a frame after receiving a remote request with the same ID
canFrame.bExtended = CAN_EXTENDED;
canFrame.btData[0] = 0x12;
canFrame.btData[1] = 0x11;
canFrame.btData[2] = 0x10;
canFrame.btDataLen = 3;
canFrame.ui32ID = 0x7654321;
LOGMSG(ZONE_INFO, L"Waiting for remote request with ID 0x%08X...\r\n", canFrame.ui32ID);
dwRet = FlexCANWriteFrame(1, CAN_DATA, CAN_TXONREMOTERX, 0, &canFrame, 10000);
LOGMSG(ZONE_INFO, L"Frame with ID 0x%08X and data %s sent. Result: %d\r\n", canFrame.ui32ID, DataToHexString(&canFrame), dwRet);
// Always exit out of loop
break;
}
//Clean up
FlexCANDeinit(1);
if (hFinishEvent)
CloseHandle(hFinishEvent);
if (hReadThread)
CloseHandle(hReadThread);
DeleteCriticalSection(&gCS);
return 0;
}
The code above is using our standard FlexCAN driver functionality and uses our (free downloadable) debug message templates for debug logging. Our High Performance FlexCAN driver supports complex ID filtering setups and a high speed (virtually unlimited) receive FIFO, among many more features.