can.c File Reference
#include <string.h>
#include "FreeRTOS.h"
#include "queue.h"
#include "task.h"
#include "can.h"
#include "LPC17xx.h"
#include "sys_config.h"
#include "lpc_sys.h"
Include dependency graph for can.c:

Data Structures

struct  can_struct_t
 Typedef of CAN queues and data. More...
 

Macros

#define CAN_TESTING   0
 
#define CAN_INDEX(can)   (can)
 CAN index: enum to struct index conversion. More...
 
#define CAN_STRUCT_PTR(can)   (&(g_can_structs[CAN_INDEX(can)]))
 
#define CAN_VALID(x)   (can1 == x || can2 == x)
 
#define CAN_ASSERT_CONCAT_(a, b)   a##b
 
#define CAN_ASSERT_CONCAT(a, b)   CAN_ASSERT_CONCAT_(a, b)
 
#define CAN_CT_ASSERT(e)   enum { CAN_ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
 
#define CAN_swap32(t32)
 
#define CAN_add_filter_list(list, ptr, end, cnt, entry_size, swap)
 

Enumerations

enum  can_intr_t {
  intr_rx = (1 << 0), intr_tx1 = (1 << 1), intr_warn = (1 << 2), intr_ovrn = (1 << 3),
  intr_wkup = (1 << 4), intr_epi = (1 << 5), intr_ali = (1 << 6), intr_berr = (1 << 7),
  intr_idi = (1 << 8), intr_tx2 = (1 << 9), intr_tx3 = (1 << 10), intr_all_tx = (intr_tx1 | intr_tx2 | intr_tx3)
}
 Interrupt masks of the CANxIER and CANxICR registers. More...
 
enum  { tx1_avail = (1 << 2), tx2_avail = (1 << 10), tx3_avail = (1 << 18), tx_all_avail = (tx1_avail | tx2_avail | tx3_avail) }
 Bit mask of SR register indicating which hardware buffer is available. More...
 
enum  { afmr_enabled = 0x00, afmr_disabled = 0x01, afmr_bypass = 0x02, afmr_fullcan = 0x04 }
 
enum  { can_mod_normal = 0x00, can_mod_reset = 0x01, can_mod_normal_tpm = (can_mod_normal | (1 << 3)), can_mod_selftest = (1 << 2) | can_mod_normal }
 CAN MOD register values. More...
 
enum  { can1_pconp_mask = (1 << 13), can2_pconp_mask = (1 << 14) }
 Mask of the PCONP register. More...
 

Functions

 CAN_CT_ASSERT (2==sizeof(can_std_id_t))
 
 CAN_CT_ASSERT (4==sizeof(can_ext_id_t))
 
 CAN_CT_ASSERT (8==sizeof(can_data_t))
 
 CAN_CT_ASSERT (16==sizeof(can_msg_t))
 
 CAN_CT_ASSERT (12==sizeof(can_fullcan_msg_t))
 
void CAN_IRQHandler (void)
 
bool CAN_init (can_t can, uint32_t baudrate_kbps, uint16_t rxq_size, uint16_t txq_size, can_void_func_t bus_off_cb, can_void_func_t data_ovr_cb)
 
bool CAN_tx (can_t can, can_msg_t *pCanMsg, uint32_t timeout_ms)
 
bool CAN_rx (can_t can, can_msg_t *pCanMsg, uint32_t timeout_ms)
 
bool CAN_is_bus_off (can_t can)
 
void CAN_reset_bus (can_t can)
 
uint16_t CAN_get_rx_watermark (can_t can)
 RX FreeRTOS Queue watermark. More...
 
uint16_t CAN_get_tx_watermark (can_t can)
 TX FreeRTOS Queue watermark. More...
 
uint16_t CAN_get_tx_count (can_t can)
 Number of messages written to the CAN HW. More...
 
uint16_t CAN_get_rx_count (can_t can)
 Number of messages successfully queued from CAN interrupt (not including dropped) More...
 
uint16_t CAN_get_rx_dropped_count (can_t can)
 
void CAN_bypass_filter_accept_all_msgs (void)
 
can_std_id_t CAN_gen_sid (can_t can, uint16_t id)
 
can_ext_id_t CAN_gen_eid (can_t can, uint32_t id)
 
bool CAN_fullcan_add_entry (can_t can, can_std_id_t id1, can_std_id_t id2)
 
can_fullcan_msg_t * CAN_fullcan_get_entry_ptr (can_std_id_t fc_id)
 
bool CAN_fullcan_read_msg_copy (can_fullcan_msg_t *pMsg, can_fullcan_msg_t *pMsgCopy)
 
uint8_t CAN_fullcan_get_num_entries (void)
 
bool CAN_setup_filter (const can_std_id_t *std_id_list, uint16_t sid_cnt, const can_std_grp_id_t *std_group_id_list, uint16_t sgp_cnt, const can_ext_id_t *ext_id_list, uint16_t eid_cnt, const can_ext_grp_id_t *ext_group_id_list, uint16_t egp_cnt)
 

Variables

can_struct_t g_can_structs [can_max] = { {LPC_CAN1}, {LPC_CAN2}}
 Structure of both CANs. More...
 

Macro Definition Documentation

#define CAN_add_filter_list (   list,
  ptr,
  end,
  cnt,
  entry_size,
  swap 
)
Value:
do { if (NULL != list) { \
if ((uint32_t)ptr + (cnt * entry_size) < end) { \
for (i = 0; i < (cnt * entry_size)/4; i++) { \
if(swap) { \
temp32 = ((uint32_t*)list) [i]; \
CAN_swap32(temp32); \
ptr[i] = temp32; \
} \
else { \
ptr[i] = ((uint32_t*)list) [i]; \
} \
} \
ptr += (cnt * entry_size)/4; \
} else { ok = false; } } } while(0)
for(loop=0;loop< len;loop=loop+4)*pulDest++
const bool ok
Definition: readme.txt:22
#define CAN_swap32(t32)
#define CAN_ASSERT_CONCAT (   a,
 
)    CAN_ASSERT_CONCAT_(a, b)
#define CAN_ASSERT_CONCAT_ (   a,
 
)    a##b
#define CAN_CT_ASSERT (   e)    enum { CAN_ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }
#define CAN_INDEX (   can)    (can)

CAN index: enum to struct index conversion.

#define CAN_STRUCT_PTR (   can)    (&(g_can_structs[CAN_INDEX(can)]))
#define CAN_swap32 (   t32)
Value:
do { \
t32 = (t32 >> 16) | (t32 << 16);\
} while (0)
#define CAN_TESTING   0

If non-zero, test code is enabled, and each message sent is self-recepted. You need to either connect a CAN transceiver, or connect RD/TD wires of the board with a 1K resistor for the tests to work.

Note that FullCAN and CAN filter is not tested together, but they both work individually.

#define CAN_VALID (   x)    (can1 == x || can2 == x)

Enumeration Type Documentation

anonymous enum

Bit mask of SR register indicating which hardware buffer is available.

Enumerator
tx1_avail 

Transmit buffer 1 is available.

tx2_avail 

Transmit buffer 2 is available.

tx3_avail 

Transmit buffer 3 is available.

tx_all_avail 
anonymous enum

Data values of the AFMR register

Note
Since AFMR is common to both controllers, when bypass mode is enabled, then ALL messages from ALL CAN controllers will be accepted

Bit1: Bypass Bit0: ACC Off 0 1 No messages accepted 1 X All messages accepted 0 0 HW Filter or FullCAN

Enumerator
afmr_enabled 

Hardware acceptance filtering.

afmr_disabled 

No messages will be accepted.

afmr_bypass 

Bypass mode, all messages will be accepted. Both 0x02 or 0x03 will work.

afmr_fullcan 

Hardware will receive and store messages per FullCAN mode.

anonymous enum

CAN MOD register values.

Enumerator
can_mod_normal 

CAN MOD register value to enable the BUS.

can_mod_reset 

CAN MOD register value to reset the BUS.

can_mod_normal_tpm 

CAN bus enabled with TPM mode bits set.

can_mod_selftest 

Used to enable global self-test.

anonymous enum

Mask of the PCONP register.

Enumerator
can1_pconp_mask 

CAN1 power on bitmask.

can2_pconp_mask 

CAN2 power on bitmask.

enum can_intr_t

Interrupt masks of the CANxIER and CANxICR registers.

Enumerator
intr_rx 

Receive.

intr_tx1 

Transmit 1.

intr_warn 

Warning (if error BUS status changes)

intr_ovrn 

Data overrun.

intr_wkup 

Wake-up.

intr_epi 

Change from error active to error passive or vice versa.

intr_ali 

Arbitration lost.

intr_berr 

Bus error (happens during each error/retry of a message)

intr_idi 

ID ready (a message was transmitted or aborted)

intr_tx2 

Transmit 2.

intr_tx3 

Transmit 3.

intr_all_tx 

Mask of the 3 transmit buffers.

Function Documentation

void CAN_bypass_filter_accept_all_msgs ( void  )

Enables CAN bypass mode to accept all messages on the bus. Either CAN filters need to be setup or this method should be called to accept CAN messages otherwise no messages will be capture at the CAN HW registers.

Note
The filter is for BOTH CANs
CAN_CT_ASSERT ( = =sizeof(can_std_id_t))
CAN_CT_ASSERT ( = =sizeof(can_ext_id_t))
CAN_CT_ASSERT ( = =sizeof(can_data_t))
CAN_CT_ASSERT ( 16  = =sizeof(can_msg_t))
CAN_CT_ASSERT ( 12  = =sizeof(can_fullcan_msg_t))
bool CAN_fullcan_add_entry ( can_t  can,
can_std_id_t  id1,
can_std_id_t  id2 
)

Adds two FullCAN entries to the acceptance filter and enables the FullCAN reception. The entries must be added in groups of 2. If the second entry is not needed, simply pass 0xFFFF to CAN_gen_sid() to generate a disabled entry.

Returns
true if successful.
Note
Only 11-bit IDs can use FullCAN.
Warning
This must be done BEFORE setting up other filters using CAN_setup_filter()
CAN BUS should not be enabled to do this because the CAN Filter is put to OFF mode while the entry is added.
Note
TO DO: Enabling fc_intr bit (FullCAN interrupts) is not yet supported
can_fullcan_msg_t* CAN_fullcan_get_entry_ptr ( can_std_id_t  fc_id)

Once all the FulLCAN entries are added, and CAN filters are setup, you can get the pointer in memory where the actual CAN message (FullCAN entry) is stored in memory.

Parameters
fc_idThe FullCAN entry originally passed to CAN_fullcan_add_entry()
uint8_t CAN_fullcan_get_num_entries ( void  )
Returns
the number of FullCAN entries being used
bool CAN_fullcan_read_msg_copy ( can_fullcan_msg_t *  fc_msg_ptr,
can_fullcan_msg_t *  msg_copy_ptr 
)

FullCAN entries may update at any time by the HW, so this method provides a means to safely read the copy of the FullCAN message.

Parameters
msg_copy_ptrThe same message returned from CAN_fullcan_get_entry_ptr()
fc_msg_ptrThe copy of the message you wish to read the data to
Returns
true if a NEW message has been captured since the last call to this method. false if HW did not receive a new message
can_ext_id_t CAN_gen_eid ( can_t  can,
uint32_t  id 
)
can_std_id_t CAN_gen_sid ( can_t  can,
uint16_t  id 
)

Generate and return the ID used to create the standard and extended id list member.

See also
CAN_setup_filter()

To generate a disabled slot, just pass 0xFFFF (id) as the message id, which will disable the message. This is used to generate an empty slot to make an even number of entries as required by the standard id filter.

uint16_t CAN_get_rx_count ( can_t  can)

Number of messages successfully queued from CAN interrupt (not including dropped)

uint16_t CAN_get_rx_dropped_count ( can_t  can)
Returns
The number of CAN messages dropped Messages can be dropped out either if the receive queue is too small, or if there is no consumer or task that dequeues the received messages quickly enough from the CAN_rx() API
uint16_t CAN_get_rx_watermark ( can_t  can)

RX FreeRTOS Queue watermark.

Watermark and counter API

uint16_t CAN_get_tx_count ( can_t  can)

Number of messages written to the CAN HW.

uint16_t CAN_get_tx_watermark ( can_t  can)

TX FreeRTOS Queue watermark.

bool CAN_init ( can_t  can,
uint32_t  baudrate_kbps,
uint16_t  rxq_size,
uint16_t  txq_size,
can_void_func_t  bus_off_cb,
can_void_func_t  data_ovr_cb 
)

Initializes the CAN controller with the given baud-rate.

Warning
This leaves the CAN BUS DISABLED!!! The next steps are :
  • Optionally, configure the FullCAN.
See also
CAN_fullcan_add_entry()
  • Optionally, configure CAN filters.
CAN_setup_filter()
Parameters
canThe can bus type.
See also
can_t
Parameters
baudrate_kbpsThe CAN Bus baud-rate, such as 100, 250, 500, 1000 Precise, external crystal should be used for higher than 100kbps
rxq_sizeThe size of the received messages queue
txq_sizeThe size of the transmit messages queue
bus_off_cbThe callback function when CAN BUS enters BUS error state
data_ovr_cbThe callback function when CAN BUS encounters data-overrun
Note
Both bus_off_cb and data_ovr_cb are optional. BUS overrun callback should be used because if user doesn't correct this, the CAN BUS will never recover once the BUS error state is entered.
Each CAN BUS has separate receive and transmit queues
Postcondition
The CAN bus is initialized, and by default, no messages are accepted until CAN filter is setup, and CAN_reset_bus() is called.

About the AFMR register : B0 B1 Filter Mode | AccOff bit | AccBP bit | CAN Rx interrupt Off Mode 1 0 No messages accepted Bypass Mode X 1 All messages accepted FullCAN 0 0 HW acceptance filtering

void CAN_IRQHandler ( void  )

Actual ISR Handler (mapped to startup file's interrupt vector function name) This interrupt is shared between CAN1, and CAN2

bool CAN_is_bus_off ( can_t  can)

CAN Bus Error and Reset API If the CAN BUS encounters error(s), it may turn off, in which case no more transmissions will take place. This must be corrected by the user.

void CAN_reset_bus ( can_t  can)
bool CAN_rx ( can_t  can,
can_msg_t *  msg,
uint32_t  timeout_ms 
)

Receive a message of the given CAN BUS.

Parameters
canThe can bus type.
See also
can_t
Parameters
msgThe CAN message
timeout_msIf FreeRTOS is running, the task will block until a message arrives. Otherwise we will poll and wait this timeout to receive a message.
Returns
true if message was captured within the given timeout.
bool CAN_setup_filter ( const can_std_id_t *  std_id_list,
uint16_t  sid_cnt,
const can_std_grp_id_t std_group_id_list,
uint16_t  sgp_cnt,
const can_ext_id_t *  ext_id_list,
uint16_t  eid_cnt,
const can_ext_grp_id_t ext_group_id_list,
uint16_t  egp_cnt 
)

Enable CAN filter for BOTH CANs; hardware doesn't allow to enable for just ONE CAN controller.

Parameters
std_id_listList of 11-bit IDs to generate an ACK for (can be NULL)
sid_cntThe size of the can_std_id_t array
std_group_id_listList of 11-bit ID groups to generate an ACK for (can be NULL)
sgp_cntThe size of the can_std_grp_id_t array
ext_id_listList of 29-bit IDs to generate an ACK for (can be NULL)
eid_cntThe size of the can_ext_id_t array
ext_group_id_listList of 29-bit ID groups to generate an ACK for (can be NULL)
egp_cntThe size of the can_ext_grp_id_t array
Warning
The list must be in ASCENDING order (lowest first, then highest). The hardware carries out its search taking for granted that the IDs are ordered from lowest to highest. If filters are wrong, CAN ISR will enter a loop and your board will restart (due to watchdog).
CAN BUS should not be enabled to do this because the CAN Filter is put to OFF mode while the entry is added.
Note
The CAN filter must be setup after the CAN controller(s) is initialized.
The size entries is limited to 2K bytes. Each entry size in bytes is :

Here is sample code that enables HW filtering of selected CAN messages. Note that some messages are for CAN2 while most are for CAN1

1 const can_std_id_t slist[] = { CAN_gen_sid(can1, 0x100), CAN_gen_sid(can1, 0x110), // 2 entries
2  CAN_gen_sid(can1, 0x120), CAN_gen_sid(can1, 0x130) // 2 entries
3  };
4 const can_std_grp_id_t sglist[] = { {CAN_gen_sid(can1, 0x150), CAN_gen_sid(can1, 0x200)}, // Group 1
5  {CAN_gen_sid(can2, 0x300), CAN_gen_sid(can2, 0x400)} // Group 2
6  };
7 const can_ext_id_t *elist = NULL; // Not used, so set it to NULL
8 const can_ext_grp_id_t eglist[] = { {CAN_gen_eid(can1, 0x3500), CAN_gen_eid(can1, 0x4500)} }; // Group 1
9 
10 CAN_setup_filter(slist, 4, sglist, 2,
11  elist, 0, eglist, 1);

Standard ID list and group list need to swapped otherwise setting the wrong filter will make the CAN ISR go into a loop for no apparent reason. It looks like the filter data is motorolla big-endian format. See "configuration example 5" in CAN chapter.

bool CAN_tx ( can_t  can,
can_msg_t *  msg,
uint32_t  timeout_ms 
)

Send a CAN message over the CAN BUS

Parameters
canThe can bus type.
See also
can_t
Parameters
msgThe CAN message
timeout_msIf FreeRTOS is running, the task will block for timeout_ms if HW buffers and the transmit queue is full. If FreeRTOS is not running the timeout is simply, ignored, and false is returned if all three HW buffers are full.

The transmit queue is only used if all three buffers of the CAN hardware are busy, in which case, the transmission complete interrupt will later send the queued msg.

Returns
If CAN message was either sent, or queued, true is returned. If all the hardware buffers are full, and the queue is full, then false is returned if timeout occurs waiting for the queue to empty.
1 can_msg_t msg;
2 msg.msg_id = 0x123;
3 msg.frame_fields.is_29bit = 1;
4 msg.frame_fields.data_len = 8; // Send 8 bytes
5 msg.data.qword = 0x1122334455667788; // Write all 8 bytes of data at once
6 CAN_tx(can_1, &msg, portMAX_DELAY);

Variable Documentation

can_struct_t g_can_structs[can_max] = { {LPC_CAN1}, {LPC_CAN2}}

Structure of both CANs.