Microchip® Advanced Software Framework

Quick Start Guide for CAN FD mode

The supported board list:

  • SAMC21 Xplained Pro

This quick start need two SAMC21 Xplained Pro boards with CAN interface connected by the jump wire: CANH - CANH and CANL - CANL.

It show how to handle standard and FD message in a CAN FD network with filter setting, message sending, receive buffer and FIFO usage and interrupt handling.

User can choose to set up two standard filter id and two extended filter id as receive filter. And then user can choose to send messages with the standard or extended filter id. If the message has been received, it will print the received data on the console. The configuration is defined in conf_can.h file with message max data length 64 and data phase baudrate 3MHz.

Setup

Prerequisites

There are no special setup requirements for this use-case.

Code

Add to the main application source file, outside of any functions:

static struct usart_module cdc_instance;
static struct can_module can_instance;
#define CAN_RX_STANDARD_FILTER_INDEX_0 0
#define CAN_RX_STANDARD_FILTER_INDEX_1 1
#define CAN_RX_STANDARD_FILTER_ID_0 0x45A
#define CAN_RX_STANDARD_FILTER_ID_0_BUFFER_INDEX 2
#define CAN_RX_STANDARD_FILTER_ID_1 0x469
#define CAN_RX_EXTENDED_FILTER_INDEX_0 0
#define CAN_RX_EXTENDED_FILTER_INDEX_1 1
#define CAN_RX_EXTENDED_FILTER_ID_0 0x100000A5
#define CAN_RX_EXTENDED_FILTER_ID_0_BUFFER_INDEX 1
#define CAN_RX_EXTENDED_FILTER_ID_1 0x10000096
#define CAN_TX_BUFFER_INDEX 0
static uint8_t tx_message_0[CONF_CAN_ELEMENT_DATA_SIZE];
static uint8_t tx_message_1[CONF_CAN_ELEMENT_DATA_SIZE];
static volatile uint32_t standard_receive_index = 0;
static volatile uint32_t extended_receive_index = 0;

Copy-paste the following setup code to your user application:

static void configure_usart_cdc(void)
{
struct usart_config config_cdc;
config_cdc.baudrate = 38400;
config_cdc.mux_setting = EDBG_CDC_SERCOM_MUX_SETTING;
config_cdc.pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0;
config_cdc.pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1;
config_cdc.pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2;
config_cdc.pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3;
stdio_serial_init(&cdc_instance, EDBG_CDC_MODULE, &config_cdc);
}
static void configure_can(void)
{
uint32_t i;
/* Initialize the memory. */
for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
tx_message_0[i] = i;
tx_message_1[i] = i + 0x80;
}
/* Set up the CAN TX/RX pins */
struct system_pinmux_config pin_config;
pin_config.mux_position = CAN_TX_MUX_SETTING;
system_pinmux_pin_set_config(CAN_TX_PIN, &pin_config);
pin_config.mux_position = CAN_RX_MUX_SETTING;
system_pinmux_pin_set_config(CAN_RX_PIN, &pin_config);
/* Initialize the module. */
struct can_config config_can;
can_init(&can_instance, CAN_MODULE, &config_can);
/* Enable interrupts for this CAN module */
system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_CAN0);
can_enable_interrupt(&can_instance, CAN_PROTOCOL_ERROR_ARBITRATION
}
static void can_set_standard_filter_0(void)
{
sd_filter.S0.bit.SFID2 = CAN_RX_STANDARD_FILTER_ID_0_BUFFER_INDEX;
sd_filter.S0.bit.SFID1 = CAN_RX_STANDARD_FILTER_ID_0;
sd_filter.S0.bit.SFEC =
can_enable_interrupt(&can_instance, CAN_RX_BUFFER_NEW_MESSAGE);
}
static void can_set_standard_filter_1(void)
{
sd_filter.S0.bit.SFID1 = CAN_RX_STANDARD_FILTER_ID_1;
can_enable_interrupt(&can_instance, CAN_RX_FIFO_0_NEW_MESSAGE);
}
static void can_set_extended_filter_0(void)
{
et_filter.F0.bit.EFID1 = CAN_RX_EXTENDED_FILTER_ID_0;
et_filter.F0.bit.EFEC =
et_filter.F1.bit.EFID2 = CAN_RX_EXTENDED_FILTER_ID_0_BUFFER_INDEX;
can_enable_interrupt(&can_instance, CAN_RX_BUFFER_NEW_MESSAGE);
}
static void can_set_extended_filter_1(void)
{
et_filter.F0.bit.EFID1 = CAN_RX_EXTENDED_FILTER_ID_1;
can_enable_interrupt(&can_instance, CAN_RX_FIFO_1_NEW_MESSAGE);
}
static void can_send_standard_message(uint32_t id_value, uint8_t *data)
{
uint32_t i;
struct can_tx_element tx_element;
tx_element.T0.reg |= CAN_TX_ELEMENT_T0_STANDARD_ID(id_value);
tx_element.T1.bit.DLC = 8;
for (i = 0; i < 8; i++) {
tx_element.data[i] = *data;
data++;
}
}
static void can_fd_send_standard_message(uint32_t id_value, uint8_t *data)
{
uint32_t i;
struct can_tx_element tx_element;
tx_element.T0.reg |= CAN_TX_ELEMENT_T0_STANDARD_ID(id_value);
for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
tx_element.data[i] = *data;
data++;
}
}
static void can_fd_send_extended_message(uint32_t id_value, uint8_t *data)
{
uint32_t i;
struct can_tx_element tx_element;
tx_element.T0.reg |= CAN_TX_ELEMENT_T0_EXTENDED_ID(id_value) |
for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
tx_element.data[i] = *data;
data++;
}
}
void CAN0_Handler(void)
{
volatile uint32_t status, i, rx_buffer_index;
if (status & CAN_RX_BUFFER_NEW_MESSAGE) {
can_clear_interrupt_status(&can_instance, CAN_RX_BUFFER_NEW_MESSAGE);
for (i = 0; i < CONF_CAN0_RX_BUFFER_NUM; i++) {
rx_buffer_index = i;
rx_buffer_index);
printf("\n\r Extended FD message received in Rx buffer. The received data is: \r\n");
} else {
printf("\n\r Standard FD message received in Rx buffer. The received data is: \r\n");
}
for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
printf(" %d",rx_element_buffer.data[i]);
}
printf("\r\n\r\n");
}
}
}
if (status & CAN_RX_FIFO_0_NEW_MESSAGE) {
can_clear_interrupt_status(&can_instance, CAN_RX_FIFO_0_NEW_MESSAGE);
standard_receive_index);
standard_receive_index);
standard_receive_index++;
if (standard_receive_index == CONF_CAN0_RX_FIFO_0_NUM) {
standard_receive_index = 0;
}
printf("\n\r Standard FD message received in FIFO 0. The received data is: \r\n");
for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
printf(" %d",rx_element_fifo_0.data[i]);
}
} else {
printf("\n\r Standard normal message received in FIFO 0. The received data is: \r\n");
for (i = 0; i < rx_element_fifo_0.R1.bit.DLC; i++) {
printf(" %d",rx_element_fifo_0.data[i]);
}
}
printf("\r\n\r\n");
}
if (status & CAN_RX_FIFO_1_NEW_MESSAGE) {
can_clear_interrupt_status(&can_instance, CAN_RX_FIFO_1_NEW_MESSAGE);
extended_receive_index);
extended_receive_index);
extended_receive_index++;
if (extended_receive_index == CONF_CAN0_RX_FIFO_1_NUM) {
extended_receive_index = 0;
}
printf("\n\r Extended FD message received in FIFO 1. The received data is: \r\n");
for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
printf(" %d",rx_element_fifo_1.data[i]);
}
printf("\r\n\r\n");
}
if ((status & CAN_PROTOCOL_ERROR_ARBITRATION)
|| (status & CAN_PROTOCOL_ERROR_DATA)) {
can_clear_interrupt_status(&can_instance, CAN_PROTOCOL_ERROR_ARBITRATION
| CAN_PROTOCOL_ERROR_DATA);
printf("Protocol error, please double check the clock in two boards. \r\n\r\n");
}
}
static void display_menu(void)
{
printf("Menu :\r\n"
" -- Select the action:\r\n"
" 0: Set standard filter ID 0: 0x45A, store into Rx buffer. \r\n"
" 1: Set standard filter ID 1: 0x469, store into Rx FIFO 0. \r\n"
" 2: Send FD standard message with ID: 0x45A and 64 byte data 0 to 63. \r\n"
" 3: Send FD standard message with ID: 0x469 and 64 byte data 128 to 191. \r\n"
" 4: Set extended filter ID 0: 0x100000A5, store into Rx buffer. \r\n"
" 5: Set extended filter ID 1: 0x10000096, store into Rx FIFO 1. \r\n"
" 6: Send FD extended message with ID: 0x100000A5 and 64 byte data 0 to 63. \r\n"
" 7: Send FD extended message with ID: 0x10000096 and 64 byte data 128 to 191. \r\n"
" a: Send normal standard message with ID: 0x469 and 8 byte data 0 to 7. \r\n"
" h: Display menu \r\n\r\n");
}

Add to user application initialization (typically the start of main()):

Workflow

  1. Create USART CDC module and CAN module software instance structure.
    static struct usart_module cdc_instance;
    static struct can_module can_instance;
  2. Define CAN standard filter setting.
    #define CAN_RX_STANDARD_FILTER_INDEX_0 0
    #define CAN_RX_STANDARD_FILTER_INDEX_1 1
    #define CAN_RX_STANDARD_FILTER_ID_0 0x45A
    #define CAN_RX_STANDARD_FILTER_ID_0_BUFFER_INDEX 2
    #define CAN_RX_STANDARD_FILTER_ID_1 0x469
    #define CAN_RX_EXTENDED_FILTER_INDEX_0 0
    #define CAN_RX_EXTENDED_FILTER_INDEX_1 1
    #define CAN_RX_EXTENDED_FILTER_ID_0 0x100000A5
    #define CAN_RX_EXTENDED_FILTER_ID_0_BUFFER_INDEX 1
    #define CAN_RX_EXTENDED_FILTER_ID_1 0x10000096
  3. Define CAN standard transfer message setting.
    #define CAN_TX_BUFFER_INDEX 0
    static uint8_t tx_message_0[CONF_CAN_ELEMENT_DATA_SIZE];
    static uint8_t tx_message_1[CONF_CAN_ELEMENT_DATA_SIZE];
  4. Define CAN standard receive message setting.
    static volatile uint32_t standard_receive_index = 0;
    static volatile uint32_t extended_receive_index = 0;
  5. Configure the USART CDC for output message.
    static void configure_usart_cdc(void)
    {
    struct usart_config config_cdc;
    config_cdc.baudrate = 38400;
    config_cdc.mux_setting = EDBG_CDC_SERCOM_MUX_SETTING;
    config_cdc.pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0;
    config_cdc.pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1;
    config_cdc.pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2;
    config_cdc.pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3;
    stdio_serial_init(&cdc_instance, EDBG_CDC_MODULE, &config_cdc);
    }
  6. Configure the CAN module.
    static void configure_can(void)
    {
    uint32_t i;
    /* Initialize the memory. */
    for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
    tx_message_0[i] = i;
    tx_message_1[i] = i + 0x80;
    }
    /* Set up the CAN TX/RX pins */
    struct system_pinmux_config pin_config;
    pin_config.mux_position = CAN_TX_MUX_SETTING;
    system_pinmux_pin_set_config(CAN_TX_PIN, &pin_config);
    pin_config.mux_position = CAN_RX_MUX_SETTING;
    system_pinmux_pin_set_config(CAN_RX_PIN, &pin_config);
    /* Initialize the module. */
    struct can_config config_can;
    can_init(&can_instance, CAN_MODULE, &config_can);
    /* Enable interrupts for this CAN module */
    system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_CAN0);
    can_enable_interrupt(&can_instance, CAN_PROTOCOL_ERROR_ARBITRATION
    }
  7. Configure the CAN standard receive filter.
    static void can_set_standard_filter_0(void)
    {
    sd_filter.S0.bit.SFID2 = CAN_RX_STANDARD_FILTER_ID_0_BUFFER_INDEX;
    sd_filter.S0.bit.SFID1 = CAN_RX_STANDARD_FILTER_ID_0;
    sd_filter.S0.bit.SFEC =
    can_enable_interrupt(&can_instance, CAN_RX_BUFFER_NEW_MESSAGE);
    }
    static void can_set_standard_filter_1(void)
    {
    sd_filter.S0.bit.SFID1 = CAN_RX_STANDARD_FILTER_ID_1;
    can_enable_interrupt(&can_instance, CAN_RX_FIFO_0_NEW_MESSAGE);
    }
    static void can_set_extended_filter_0(void)
    {
    et_filter.F0.bit.EFID1 = CAN_RX_EXTENDED_FILTER_ID_0;
    et_filter.F0.bit.EFEC =
    et_filter.F1.bit.EFID2 = CAN_RX_EXTENDED_FILTER_ID_0_BUFFER_INDEX;
    can_enable_interrupt(&can_instance, CAN_RX_BUFFER_NEW_MESSAGE);
    }
    static void can_set_extended_filter_1(void)
    {
    et_filter.F0.bit.EFID1 = CAN_RX_EXTENDED_FILTER_ID_1;
    can_enable_interrupt(&can_instance, CAN_RX_FIFO_1_NEW_MESSAGE);
    }
  8. Configure the CAN transfer message.
    static void can_send_standard_message(uint32_t id_value, uint8_t *data)
    {
    uint32_t i;
    struct can_tx_element tx_element;
    tx_element.T0.reg |= CAN_TX_ELEMENT_T0_STANDARD_ID(id_value);
    tx_element.T1.bit.DLC = 8;
    for (i = 0; i < 8; i++) {
    tx_element.data[i] = *data;
    data++;
    }
    }
    static void can_fd_send_standard_message(uint32_t id_value, uint8_t *data)
    {
    uint32_t i;
    struct can_tx_element tx_element;
    tx_element.T0.reg |= CAN_TX_ELEMENT_T0_STANDARD_ID(id_value);
    for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
    tx_element.data[i] = *data;
    data++;
    }
    }
    static void can_fd_send_extended_message(uint32_t id_value, uint8_t *data)
    {
    uint32_t i;
    struct can_tx_element tx_element;
    tx_element.T0.reg |= CAN_TX_ELEMENT_T0_EXTENDED_ID(id_value) |
    for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
    tx_element.data[i] = *data;
    data++;
    }
    }
  9. Implement the interrupt handler function.
    void CAN0_Handler(void)
    {
    volatile uint32_t status, i, rx_buffer_index;
    if (status & CAN_RX_BUFFER_NEW_MESSAGE) {
    can_clear_interrupt_status(&can_instance, CAN_RX_BUFFER_NEW_MESSAGE);
    for (i = 0; i < CONF_CAN0_RX_BUFFER_NUM; i++) {
    rx_buffer_index = i;
    rx_buffer_index);
    printf("\n\r Extended FD message received in Rx buffer. The received data is: \r\n");
    } else {
    printf("\n\r Standard FD message received in Rx buffer. The received data is: \r\n");
    }
    for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
    printf(" %d",rx_element_buffer.data[i]);
    }
    printf("\r\n\r\n");
    }
    }
    }
    if (status & CAN_RX_FIFO_0_NEW_MESSAGE) {
    can_clear_interrupt_status(&can_instance, CAN_RX_FIFO_0_NEW_MESSAGE);
    standard_receive_index);
    standard_receive_index);
    standard_receive_index++;
    if (standard_receive_index == CONF_CAN0_RX_FIFO_0_NUM) {
    standard_receive_index = 0;
    }
    printf("\n\r Standard FD message received in FIFO 0. The received data is: \r\n");
    for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
    printf(" %d",rx_element_fifo_0.data[i]);
    }
    } else {
    printf("\n\r Standard normal message received in FIFO 0. The received data is: \r\n");
    for (i = 0; i < rx_element_fifo_0.R1.bit.DLC; i++) {
    printf(" %d",rx_element_fifo_0.data[i]);
    }
    }
    printf("\r\n\r\n");
    }
    if (status & CAN_RX_FIFO_1_NEW_MESSAGE) {
    can_clear_interrupt_status(&can_instance, CAN_RX_FIFO_1_NEW_MESSAGE);
    extended_receive_index);
    extended_receive_index);
    extended_receive_index++;
    if (extended_receive_index == CONF_CAN0_RX_FIFO_1_NUM) {
    extended_receive_index = 0;
    }
    printf("\n\r Extended FD message received in FIFO 1. The received data is: \r\n");
    for (i = 0; i < CONF_CAN_ELEMENT_DATA_SIZE; i++) {
    printf(" %d",rx_element_fifo_1.data[i]);
    }
    printf("\r\n\r\n");
    }
    if ((status & CAN_PROTOCOL_ERROR_ARBITRATION)
    || (status & CAN_PROTOCOL_ERROR_DATA)) {
    can_clear_interrupt_status(&can_instance, CAN_PROTOCOL_ERROR_ARBITRATION
    | CAN_PROTOCOL_ERROR_DATA);
    printf("Protocol error, please double check the clock in two boards. \r\n\r\n");
    }
    }
  10. User menu function.
    static void display_menu(void)
    {
    printf("Menu :\r\n"
    " -- Select the action:\r\n"
    " 0: Set standard filter ID 0: 0x45A, store into Rx buffer. \r\n"
    " 1: Set standard filter ID 1: 0x469, store into Rx FIFO 0. \r\n"
    " 2: Send FD standard message with ID: 0x45A and 64 byte data 0 to 63. \r\n"
    " 3: Send FD standard message with ID: 0x469 and 64 byte data 128 to 191. \r\n"
    " 4: Set extended filter ID 0: 0x100000A5, store into Rx buffer. \r\n"
    " 5: Set extended filter ID 1: 0x10000096, store into Rx FIFO 1. \r\n"
    " 6: Send FD extended message with ID: 0x100000A5 and 64 byte data 0 to 63. \r\n"
    " 7: Send FD extended message with ID: 0x10000096 and 64 byte data 128 to 191. \r\n"
    " a: Send normal standard message with ID: 0x469 and 8 byte data 0 to 7. \r\n"
    " h: Display menu \r\n\r\n");
    }

Use Case

Code

Copy-paste the following code to your user application:

while(1) {
scanf("%c", (char *)&key);
switch (key) {
case 'h':
break;
case '0':
printf(" 0: Set standard filter ID 0: 0x45A, store into Rx buffer. \r\n");
break;
case '1':
printf(" 1: Set standard filter ID 1: 0x469, store into Rx FIFO 0. \r\n");
break;
case '2':
printf(" 2: Send standard message with ID: 0x45A and 64 byte data 0 to 63. \r\n");
break;
case '3':
printf(" 3: Send standard message with ID: 0x469 and 64 byte data 128 to 191. \r\n");
break;
case '4':
printf(" 4: Set extended filter ID 0: 0x100000A5, store into Rx buffer. \r\n");
break;
case '5':
printf(" 5: Set extended filter ID 1: 0x10000096, store into Rx FIFO 1. \r\n");
break;
case '6':
printf(" 6: Send extended message with ID: 0x100000A5 and 64 byte data 0 to 63. \r\n");
break;
case '7':
printf(" 7: Send extended message with ID: 0x10000096 and 64 byte data 128 to 191. \r\n");
break;
case 'a':
printf(" a: Send normal standard message with ID: 0x469 and 8 byte data 0 to 7. \r\n");
break;
default:
break;
}
}

Workflow

  1. Set up CAN module.
  2. Display user menu .
  3. Enter the main loop, wait for the user input .
    while(1) {
    scanf("%c", (char *)&key);
    switch (key) {
    case 'h':
    break;
    case '0':
    printf(" 0: Set standard filter ID 0: 0x45A, store into Rx buffer. \r\n");
    break;
    case '1':
    printf(" 1: Set standard filter ID 1: 0x469, store into Rx FIFO 0. \r\n");
    break;
    case '2':
    printf(" 2: Send standard message with ID: 0x45A and 64 byte data 0 to 63. \r\n");
    break;
    case '3':
    printf(" 3: Send standard message with ID: 0x469 and 64 byte data 128 to 191. \r\n");
    break;
    case '4':
    printf(" 4: Set extended filter ID 0: 0x100000A5, store into Rx buffer. \r\n");
    break;
    case '5':
    printf(" 5: Set extended filter ID 1: 0x10000096, store into Rx FIFO 1. \r\n");
    break;
    case '6':
    printf(" 6: Send extended message with ID: 0x100000A5 and 64 byte data 0 to 63. \r\n");
    break;
    case '7':
    printf(" 7: Send extended message with ID: 0x10000096 and 64 byte data 128 to 191. \r\n");
    break;
    case 'a':
    printf(" a: Send normal standard message with ID: 0x469 and 8 byte data 0 to 7. \r\n");
    break;
    default:
    break;
    }
    }