Microchip® Advanced Software Framework

Quick Start Guide for CAN normal 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 message in a normal CAN 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 8 and baudrate 500KHz.

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);
}
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 =
}
static void can_set_standard_filter_1(void)
{
sd_filter.S0.bit.SFID1 = CAN_RX_STANDARD_FILTER_ID_1;
}
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;
}
static void can_set_extended_filter_1(void)
{
et_filter.F0.bit.EFID1 = CAN_RX_EXTENDED_FILTER_ID_1;
}
static void can_send_standard_message(uint32_t id_value, uint8_t *data,
uint32_t data_length)
{
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 = data_length;
for (i = 0; i < data_length; i++) {
tx_element.data[i] = *data;
data++;
}
}
static void can_send_extended_message(uint32_t id_value, uint8_t *data,
uint32_t data_length)
{
uint32_t i;
struct can_tx_element tx_element;
tx_element.T0.reg |= CAN_TX_ELEMENT_T0_EXTENDED_ID(id_value) |
tx_element.T1.bit.DLC = data_length;
for (i = 0; i < data_length; 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 message received in Rx buffer. The received data is: \r\n");
} else {
printf("\n\r Standard message received in Rx buffer. The received data is: \r\n");
}
for (i = 0; i < rx_element_buffer.R1.bit.DLC; 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 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 message received in FIFO 1. The received data is: \r\n");
for (i = 0; i < rx_element_fifo_1.R1.bit.DLC; i++) {
printf(" %d",rx_element_fifo_1.data[i]);
}
printf("\r\n\r\n");
}
|| (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 standard message with ID: 0x45A and 4 byte data 0 to 3. \r\n"
" 3: Send standard message with ID: 0x469 and 4 byte data 128 to 131. \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 extended message with ID: 0x100000A5 and 8 byte data 0 to 7. \r\n"
" 7: Send extended message with ID: 0x10000096 and 8 byte data 128 to 135. \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 data_length)
    {
    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 = data_length;
    for (i = 0; i < data_length; i++) {
    tx_element.data[i] = *data;
    data++;
    }
    }
    static void can_send_extended_message(uint32_t id_value, uint8_t *data,
    uint32_t data_length)
    {
    uint32_t i;
    struct can_tx_element tx_element;
    tx_element.T0.reg |= CAN_TX_ELEMENT_T0_EXTENDED_ID(id_value) |
    tx_element.T1.bit.DLC = data_length;
    for (i = 0; i < data_length; 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 message received in Rx buffer. The received data is: \r\n");
    } else {
    printf("\n\r Standard message received in Rx buffer. The received data is: \r\n");
    }
    for (i = 0; i < rx_element_buffer.R1.bit.DLC; 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 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 message received in FIFO 1. The received data is: \r\n");
    for (i = 0; i < rx_element_fifo_1.R1.bit.DLC; 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 standard message with ID: 0x45A and 4 byte data 0 to 3. \r\n"
    " 3: Send standard message with ID: 0x469 and 4 byte data 128 to 131. \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 extended message with ID: 0x100000A5 and 8 byte data 0 to 7. \r\n"
    " 7: Send extended message with ID: 0x10000096 and 8 byte data 128 to 135. \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 4 byte data 0 to 3. \r\n");
CONF_CAN_ELEMENT_DATA_SIZE / 2);
break;
case '3':
printf(" 3: Send standard message with ID: 0x469 and 4 byte data 128 to 131. \r\n");
CONF_CAN_ELEMENT_DATA_SIZE / 2);
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 8 byte data 0 to 7. \r\n");
CONF_CAN_ELEMENT_DATA_SIZE);
break;
case '7':
printf(" 7: Send extended message with ID: 0x10000096 and 8 byte data 128 to 135. \r\n");
CONF_CAN_ELEMENT_DATA_SIZE);
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 4 byte data 0 to 3. \r\n");
    CONF_CAN_ELEMENT_DATA_SIZE / 2);
    break;
    case '3':
    printf(" 3: Send standard message with ID: 0x469 and 4 byte data 128 to 131. \r\n");
    CONF_CAN_ELEMENT_DATA_SIZE / 2);
    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 8 byte data 0 to 7. \r\n");
    CONF_CAN_ELEMENT_DATA_SIZE);
    break;
    case '7':
    printf(" 7: Send extended message with ID: 0x10000096 and 8 byte data 128 to 135. \r\n");
    CONF_CAN_ELEMENT_DATA_SIZE);
    break;
    default:
    break;
    }
    }