2.61 Controller Area Network (MCAN)

The Controller Area Network (MCAN) performs communication according to ISO 11898-1:2015 and to Bosch CAN-FD specification. Additional transceiver hardware is required for connection to the physical layer.

All functions concerning the handling of messages are implemented by the Rx Handler and the Tx Handler. The Rx Handler manages message acceptance filtering, the transfer of received messages from the CAN core to the Message RAM, as well as providing receive message status information. The Tx Handler is responsible for the transfer of transmit messages from the Message RAM to the CAN core, as well as providing transmit status information. Acceptance filtering is implemented by a combination of up to 128 filter elements, where each element can be configured as a range, as a bit mask, or as a dedicated ID filter.

Using The Library

The MCAN library supports the Normal and CAN-FD modes. The MCAN Normal or CAN-FD mode can transfer message in a polling or an interrupt mode.

MCAN Message RAM Configuration

Allocate MCAN Message RAM configuration in contiguous non-cacheable buffer in the application.

For example in SAME70, uint8_t Mcan1MessageRAM[MCAN1_MESSAGE_RAM_CONFIG_SIZE] attribute((aligned (32)))attribute((space(data), section (".ram_nocache")));

For example in SAMA5D2, uint8_t Mcan0MessageRAM[MCAN0_MESSAGE_RAM_CONFIG_SIZE] attribute((aligned (32))) attribute((section(".region_nocache")))

If cache is enabled then non-cacheable section "ram_nocache" or "region_nocache" should be added in linker script (if non-cacheable \section is not present in linker script).

MCAN polling mode:

#include <stddef.h>                     // Defines NULL
#include <stdbool.h>                    // Defines true
#include <stdlib.h>                     // Defines EXIT_FAILURE
#include "definitions.h"                // SYS function prototypes

uint8_t Mcan1MessageRAM[MCAN1_MESSAGE_RAM_CONFIG_SIZE] __attribute__((aligned (32)))__attribute__((space(data), section (".ram_nocache")));
        
/* Standard identifier id[28:18]*/
#define WRITE_ID(id) (id << 18)
#define READ_ID(id)  (id >> 18)

static uint32_t status = 0;
static uint8_t loop_count = 0;
static uint8_t user_input = 0;

static uint8_t txFiFo[MCAN1_TX_FIFO_BUFFER_SIZE];
static uint8_t rxFiFo0[MCAN1_RX_FIFO0_SIZE];
static uint8_t rxFiFo1[MCAN1_RX_FIFO1_SIZE];
static uint8_t rxBuffer[MCAN1_RX_BUFFER_SIZE];

// *****************************************************************************
// *****************************************************************************
// Section: Local functions
// *****************************************************************************
// *****************************************************************************

/* Message Length to Data length code */
static uint8_t MCANLengthToDlcGet(uint8_t length)
{
    uint8_t dlc = 0;

    if (length <= 8U)
    {
        dlc = length;
    }
    else if (length <= 12U)
    {
        dlc = 0x9U;
    }
    else if (length <= 16U)
    {
        dlc = 0xAU;
    }
    else if (length <= 20U)
    {
        dlc = 0xBU;
    }
    else if (length <= 24U)
    {
        dlc = 0xCU;
    }
    else if (length <= 32U)
    {
        dlc = 0xDU;
    }
    else if (length <= 48U)
    {
        dlc = 0xEU;
    }
    else
    {
        dlc = 0xFU;
    }
    return dlc;
}

/* Data length code to Message Length */
static uint8_t MCANDlcToLengthGet(uint8_t dlc)
{
    uint8_t msgLength[] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U};
    return msgLength[dlc];
}

/* Menu */
static void display_menu(void)
{
	printf("Menu :\r\n"
	       "  -- Select the action:\r\n"
	       "  0: Send FD standard message with ID: 0x45A and 64 byte data 0 to 63. \r\n"
	       "  1: Send FD standard message with ID: 0x469 and 64 byte data 128 to 191. \r\n"
	       "  2: Send FD extended message with ID: 0x100000A5 and 64 byte data 0 to 63. \r\n"
	       "  3: Send FD extended message with ID: 0x10000096 and 64 byte data 128 to 191. \r\n"
	       "  4: Send normal standard message with ID: 0x469 and 8 byte data 0 to 7. \r\n"
	       "  m: Display menu \r\n\r\n");
}

/* Print Rx Message */
static void print_message(uint8_t numberOfMessage, MCAN_RX_BUFFER *rxBuf, uint8_t rxBufLen, uint8_t rxFifoBuf)
{
    uint8_t length = 0;
    uint8_t msgLength = 0;
    uint32_t id = 0;

    if (rxFifoBuf == 0)
        printf(" Rx FIFO0 :");
    else if (rxFifoBuf == 1)
        printf(" Rx FIFO1 :");
    else if (rxFifoBuf == 2)
        printf(" Rx Buffer :");

    for (uint8_t count = 0; count < numberOfMessage; count++)
    {
        /* Print message to Console */
        printf(" New Message Received\r\n");
        id = rxBuf->xtd ? rxBuf->id : READ_ID(rxBuf->id);
        msgLength = MCANDlcToLengthGet(rxBuf->dlc);
        length = msgLength;
        printf(" Message - ID : 0x%x Length : 0x%x ", (unsigned int)id, (unsigned int)msgLength);
        printf("Message : ");
        while(length)
        {
            printf("0x%x ", rxBuf->data[msgLength - length--]);
        }
        printf("\r\n");
        rxBuf += rxBufLen;
    }
}

// *****************************************************************************
// *****************************************************************************
// Section: Main Entry Point
// *****************************************************************************
// *****************************************************************************

int main ( void )
{
    MCAN_TX_BUFFER *txBuffer = NULL;
    uint8_t        bufferNumber = 0;
    uint8_t        numberOfMessage = 0;

    /* Initialize all modules */
    SYS_Initialize ( NULL );

    printf(" ------------------------------ \r\n");
    printf("            MCAN FD Demo          \r\n");
    printf(" ------------------------------ \r\n");
    
    /* Set Message RAM Configuration */
    MCAN1_MessageRAMConfigSet(Mcan1MessageRAM);

    display_menu();
     
    while ( true )
    {
        /* Rx Buffers */
        if (MCAN1_InterruptGet(MCAN_INTERRUPT_DRX_MASK))
        {    
            MCAN1_InterruptClear(MCAN_INTERRUPT_DRX_MASK);

            /* Check MCAN Status */
            status = MCAN1_ErrorGet();

            if (((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_NONE) || ((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_LEC_NO_CHANGE))
            {
                if (MCAN1_RxBufferNumberGet(&bufferNumber))
                {
                    memset(rxBuffer, 0x00, MCAN1_RX_BUFFER_ELEMENT_SIZE);
                    if (MCAN1_MessageReceive(bufferNumber, (MCAN_RX_BUFFER *)rxBuffer) == true)
                    {
                        print_message(1, (MCAN_RX_BUFFER *)rxBuffer, MCAN1_RX_BUFFER_ELEMENT_SIZE, 2);
                    }
                    else
                    {
                        printf(" Error in received message\r\n");
                    }
                }
            }
            else
            {
                printf(" Error in received message\r\n");
            }
        }

        /* Rx FIFO0 */
        if (MCAN1_InterruptGet(MCAN_INTERRUPT_RF0N_MASK))
        {    
            MCAN1_InterruptClear(MCAN_INTERRUPT_RF0N_MASK);

            /* Check MCAN Status */
            status = MCAN1_ErrorGet();

            if (((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_NONE) || ((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_LEC_NO_CHANGE))
            {
                numberOfMessage = MCAN1_RxFifoFillLevelGet(MCAN_RX_FIFO_0);
                if (numberOfMessage != 0)
                {
                    memset(rxFiFo0, 0x00, (numberOfMessage * MCAN1_RX_FIFO0_ELEMENT_SIZE));
                    if (MCAN1_MessageReceiveFifo(MCAN_RX_FIFO_0, numberOfMessage, (MCAN_RX_BUFFER *)rxFiFo0) == true)
                    {
                        print_message(numberOfMessage, (MCAN_RX_BUFFER *)rxFiFo0, MCAN1_RX_FIFO0_ELEMENT_SIZE, 0);
                    }
                    else
                    {
                        printf(" Error in received message\r\n");
                    }
                }
            }
            else
            {
                printf(" Error in received message\r\n");
            }
        }

        /* Rx FIFO1 */
        if (MCAN1_InterruptGet(MCAN_INTERRUPT_RF1N_MASK))
        {    
            MCAN1_InterruptClear(MCAN_INTERRUPT_RF1N_MASK);

            /* Check MCAN Status */
            status = MCAN1_ErrorGet();

            if (((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_NONE) || ((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_LEC_NO_CHANGE))
            {
                numberOfMessage = MCAN1_RxFifoFillLevelGet(MCAN_RX_FIFO_1);
                if (numberOfMessage != 0)
                {
                    memset(rxFiFo1, 0x00, (numberOfMessage * MCAN1_RX_FIFO1_ELEMENT_SIZE));
                    if (MCAN1_MessageReceiveFifo(MCAN_RX_FIFO_1, numberOfMessage, (MCAN_RX_BUFFER *)rxFiFo1) == true)
                    {
                        print_message(numberOfMessage, (MCAN_RX_BUFFER *)rxFiFo1, MCAN1_RX_FIFO1_ELEMENT_SIZE, 1);
                    }
                    else
                    {
                        printf(" Error in received message\r\n");
                    }
                }
            }
            else
            {
                printf(" Error in received message\r\n");
            }
        }

        /* User input */
        if (USART1_ReceiverIsReady() == false)
        {
            continue;
        }
        user_input = (uint8_t)USART1_ReadByte();

        switch (user_input)
        {
            case '0':
                memset(txFiFo, 0x00, MCAN1_TX_FIFO_BUFFER_ELEMENT_SIZE);
                txBuffer = (MCAN_TX_BUFFER *)txFiFo;
                txBuffer->id = WRITE_ID(0x45A);
                txBuffer->dlc = MCANLengthToDlcGet(64);
                txBuffer->fdf = 1;
                txBuffer->brs = 1;
                for (loop_count = 0; loop_count < 64; loop_count++){
                    txBuffer->data[loop_count] = loop_count;
                }                
                printf("  0: Send FD standard message with ID: 0x45A and 64 byte data 0 to 63.\r\n");
                if (MCAN1_MessageTransmitFifo(1, txBuffer) == true)
                {    
                    printf(" Success \r\n");
                }
                else
                {
                    printf(" Failed \r\n");
                }             
                break;  
            case '1':
                memset(txFiFo, 0x00, MCAN1_TX_FIFO_BUFFER_ELEMENT_SIZE);
                txBuffer = (MCAN_TX_BUFFER *)txFiFo;
                txBuffer->id = WRITE_ID(0x469);
                txBuffer->dlc = MCANLengthToDlcGet(64);
                txBuffer->fdf = 1;
                txBuffer->brs = 1;
                for (loop_count = 128; loop_count < 192; loop_count++){
                    txBuffer->data[loop_count - 128] = loop_count;
                }                
                printf("  1: Send FD standard message with ID: 0x469 and 64 byte data 128 to 191.\r\n");
                if (MCAN1_MessageTransmitFifo(1, txBuffer) == true)
                {    
                    printf(" Success \r\n");
                }
                else
                {
                    printf(" Failed \r\n");
                }    
                break;
            case '2': 
                memset(txFiFo, 0x00, MCAN1_TX_FIFO_BUFFER_ELEMENT_SIZE);
                txBuffer = (MCAN_TX_BUFFER *)txFiFo;
                txBuffer->id = 0x100000A5;
                txBuffer->dlc = MCANLengthToDlcGet(64);
                txBuffer->xtd = 1;
                txBuffer->fdf = 1;
                txBuffer->brs = 1;
                for (loop_count = 0; loop_count < 64; loop_count++){
                    txBuffer->data[loop_count] = loop_count;
                }
                printf("  2: Send FD extended message with ID: 0x100000A5 and 64 byte data 0 to 63.\r\n");
                if (MCAN1_MessageTransmitFifo(1, txBuffer) == true)
                {    
                    printf(" Success \r\n");
                }
                else
                {
                    printf(" Failed \r\n");
                }             
                break;
            case '3':
                memset(txFiFo, 0x00, MCAN1_TX_FIFO_BUFFER_ELEMENT_SIZE);
                txBuffer = (MCAN_TX_BUFFER *)txFiFo;
                txBuffer->id = 0x10000096;
                txBuffer->dlc = MCANLengthToDlcGet(64);
                txBuffer->xtd = 1;
                txBuffer->fdf = 1;
                txBuffer->brs = 1;
                for (loop_count = 128; loop_count < 192; loop_count++){
                    txBuffer->data[loop_count - 128] = loop_count;
                }
                printf("  3: Send FD extended message with ID: 0x10000096 and 64 byte data 128 to 191.\r\n");
                if (MCAN1_MessageTransmitFifo(1, txBuffer) == true)
                {    
                    printf(" Success \r\n");
                }
                else
                {
                    printf(" Failed \r\n");
                }             
                break;
            
            case '4':
                memset(txFiFo, 0x00, MCAN1_TX_FIFO_BUFFER_ELEMENT_SIZE);
                txBuffer = (MCAN_TX_BUFFER *)txFiFo;
                txBuffer->id = WRITE_ID(0x469);
                txBuffer->dlc = 8;
                for (loop_count = 0; loop_count < 8; loop_count++){
                    txBuffer->data[loop_count] = loop_count;
                }                
                printf("  4: Send normal standard message with ID: 0x469 and 8 byte data 0 to 7.\r\n");
                if (MCAN1_MessageTransmitFifo(1, txBuffer) == true)
                {    
                    printf(" Success \r\n");
                }
                else
                {
                    printf(" Failed \r\n");
                }             
                break;                 

            case 'm':
            case 'M':
                display_menu();
                break;
                
            default:
                printf(" Invalid Input \r\n");
                break;
        }  
    }

    /* Execution should not come here during normal operation */

    return ( EXIT_FAILURE );
}

MCAN interrupt mode:

#include <stddef.h>                     // Defines NULL
#include <stdbool.h>                    // Defines true
#include <stdlib.h>                     // Defines EXIT_FAILURE
#include "definitions.h"                // SYS function prototypes

uint8_t Mcan1MessageRAM[MCAN1_MESSAGE_RAM_CONFIG_SIZE] __attribute__((aligned (32)))__attribute__((space(data), section (".ram_nocache")));

/* Standard identifier id[28:18]*/
#define WRITE_ID(id) (id << 18)
#define READ_ID(id)  (id >> 18)

/* Application's state machine enum */
typedef enum
{
    APP_STATE_MCAN_RECEIVE,
    APP_STATE_MCAN_TRANSMIT,
    APP_STATE_MCAN_IDLE,
    APP_STATE_MCAN_XFER_SUCCESSFUL,
    APP_STATE_MCAN_XFER_ERROR,
    APP_STATE_MCAN_USER_INPUT
} APP_STATES;

/* Variable to save Tx/Rx transfer status and context */
static uint32_t status = 0;
static uint32_t xferContext = 0;
/* Variable to save Tx/Rx message */
static uint8_t loop_count = 0;
static uint8_t user_input = 0;
/* Variable to save application state */
volatile static APP_STATES state = APP_STATE_MCAN_USER_INPUT;

static uint8_t txFiFo[MCAN1_TX_FIFO_BUFFER_SIZE];
static uint8_t rxFiFo0[MCAN1_RX_FIFO0_SIZE];
static uint8_t rxFiFo1[MCAN1_RX_FIFO1_SIZE];
static uint8_t rxBuffer[MCAN1_RX_BUFFER_SIZE];

// *****************************************************************************
// *****************************************************************************
// Section: Local functions
// *****************************************************************************
// *****************************************************************************

/* Message Length to Data length code */
static uint8_t MCANLengthToDlcGet(uint8_t length)
{
    uint8_t dlc = 0;

    if (length <= 8U)
    {
        dlc = length;
    }
    else if (length <= 12U)
    {
        dlc = 0x9U;
    }
    else if (length <= 16U)
    {
        dlc = 0xAU;
    }
    else if (length <= 20U)
    {
        dlc = 0xBU;
    }
    else if (length <= 24U)
    {
        dlc = 0xCU;
    }
    else if (length <= 32U)
    {
        dlc = 0xDU;
    }
    else if (length <= 48U)
    {
        dlc = 0xEU;
    }
    else
    {
        dlc = 0xFU;
    }
    return dlc;
}

/* Data length code to Message Length */
static uint8_t MCANDlcToLengthGet(uint8_t dlc)
{
    uint8_t msgLength[] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U};
    return msgLength[dlc];
}

/* Menu */
static void display_menu(void)
{
	printf("Menu :\r\n"
	       "  -- Select the action:\r\n"
	       "  0: Send FD standard message with ID: 0x45A and 64 byte data 0 to 63. \r\n"
	       "  1: Send FD standard message with ID: 0x469 and 64 byte data 128 to 191. \r\n"
	       "  2: Send FD extended message with ID: 0x100000A5 and 64 byte data 0 to 63. \r\n"
	       "  3: Send FD extended message with ID: 0x10000096 and 64 byte data 128 to 191. \r\n"
	       "  4: Send normal standard message with ID: 0x469 and 8 byte data 0 to 7. \r\n"
	       "  m: Display menu \r\n\r\n");
}

/* Print Rx Message */
static void print_message(uint8_t numberOfMessage, MCAN_RX_BUFFER *rxBuf, uint8_t rxBufLen, uint8_t rxFifoBuf)
{
    uint8_t length = 0;
    uint8_t msgLength = 0;
    uint32_t id = 0;

    if (rxFifoBuf == 0)
        printf(" Rx FIFO0 :");
    else if (rxFifoBuf == 1)
        printf(" Rx FIFO1 :");
    else if (rxFifoBuf == 2)
        printf(" Rx Buffer :");

    for (uint8_t count = 0; count < numberOfMessage; count++)
    {
        /* Print message to Console */
        printf(" New Message Received\r\n");
        id = rxBuf->xtd ? rxBuf->id : READ_ID(rxBuf->id);
        msgLength = MCANDlcToLengthGet(rxBuf->dlc);
        length = msgLength;
        printf(" Message - Timestamp : 0x%x ID : 0x%x Length : 0x%x ", (unsigned int)rxBuf->rxts, (unsigned int)id, (unsigned int)msgLength);
        printf("Message : ");
        while(length)
        {
            printf("0x%x ", rxBuf->data[msgLength - length--]);
        }
        printf("\r\n");
        rxBuf += rxBufLen;
    }
}

/* This function will be called by MCAN PLIB when transfer is completed from Tx FIFO */
void APP_MCAN_TxFifoCallback(uintptr_t context)
{
    xferContext = context;

    /* Check MCAN Status */
    status = MCAN1_ErrorGet();

    if (((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_NONE) || ((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_LEC_NO_CHANGE))
    {
        switch ((APP_STATES)context)
        {
            case APP_STATE_MCAN_TRANSMIT:
            {
                state = APP_STATE_MCAN_XFER_SUCCESSFUL;
                break;
            }
            default:
                break;
        }
    }
    else
    {
        state = APP_STATE_MCAN_XFER_ERROR;
    }
}

/* This function will be called by MCAN PLIB when Message received in Rx Buffer */
void APP_MCAN_RxBufferCallback(uint8_t bufferNumber, uintptr_t context)
{
    xferContext = context;

    /* Check MCAN Status */
    status = MCAN1_ErrorGet();

    if (((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_NONE) || ((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_LEC_NO_CHANGE))
    {
        switch ((APP_STATES)context)
        {
            case APP_STATE_MCAN_RECEIVE:
            {
                memset(rxBuffer, 0x00, MCAN1_RX_BUFFER_ELEMENT_SIZE);
                if (MCAN1_MessageReceive(bufferNumber, (MCAN_RX_BUFFER *)rxBuffer) == true)
                {
                    print_message(1, (MCAN_RX_BUFFER *)rxBuffer, MCAN1_RX_BUFFER_ELEMENT_SIZE, 2);
                    state = APP_STATE_MCAN_XFER_SUCCESSFUL;
                }
                else
                {
                    state = APP_STATE_MCAN_XFER_ERROR;
                }
                break;
            }
            default:
                break;
        }
    }
    else
    {
        state = APP_STATE_MCAN_XFER_ERROR;
    }
}

/* This function will be called by MCAN PLIB when Message received in Rx FIFO0 */
void APP_MCAN_RxFifo0Callback(uint8_t numberOfMessage, uintptr_t context)
{
    xferContext = context;

    /* Check MCAN Status */
    status = MCAN1_ErrorGet();

    if (((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_NONE) || ((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_LEC_NO_CHANGE))
    {
        switch ((APP_STATES)context)
        {
            case APP_STATE_MCAN_RECEIVE:
            {
                memset(rxFiFo0, 0x00, (numberOfMessage * MCAN1_RX_FIFO0_ELEMENT_SIZE));
                if (MCAN1_MessageReceiveFifo(MCAN_RX_FIFO_0, numberOfMessage, (MCAN_RX_BUFFER *)rxFiFo0) == true)
                {
                    print_message(numberOfMessage, (MCAN_RX_BUFFER *)rxFiFo0, MCAN1_RX_FIFO0_ELEMENT_SIZE, 0);
                    state = APP_STATE_MCAN_XFER_SUCCESSFUL;
                }
                else
                {
                    state = APP_STATE_MCAN_XFER_ERROR;
                }
                break;
            }
            default:
                break;
        }
    }
    else
    {
        state = APP_STATE_MCAN_XFER_ERROR;
    }
}

/* This function will be called by MCAN PLIB when Message received in Rx FIFO1 */
void APP_MCAN_RxFifo1Callback(uint8_t numberOfMessage, uintptr_t context)
{
    xferContext = context;

    /* Check MCAN Status */
    status = MCAN1_ErrorGet();

    if (((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_NONE) || ((status & MCAN_PSR_LEC_Msk) == MCAN_ERROR_LEC_NO_CHANGE))
    {
        switch ((APP_STATES)context)
        {
            case APP_STATE_MCAN_RECEIVE:
            {
                memset(rxFiFo1, 0x00, (numberOfMessage * MCAN1_RX_FIFO1_ELEMENT_SIZE));
                if (MCAN1_MessageReceiveFifo(MCAN_RX_FIFO_1, numberOfMessage, (MCAN_RX_BUFFER *)rxFiFo1) == true)
                {
                    print_message(numberOfMessage, (MCAN_RX_BUFFER *)rxFiFo1, MCAN1_RX_FIFO1_ELEMENT_SIZE, 1);
                    state = APP_STATE_MCAN_XFER_SUCCESSFUL;
                }
                else
                {
                    state = APP_STATE_MCAN_XFER_ERROR;
                }
                break;
            }
            default:
                break;
        }
    }
    else
    {
        state = APP_STATE_MCAN_XFER_ERROR;
    }
}

// *****************************************************************************
// *****************************************************************************
// Section: Main Entry Point
// *****************************************************************************
// *****************************************************************************

int main ( void )
{
    MCAN_TX_BUFFER *txBuffer = NULL;

    /* Initialize all modules */
    SYS_Initialize ( NULL );

    printf(" ------------------------------ \r\n");
    printf("        MCAN FD Demo            \r\n");
    printf(" ------------------------------ \r\n");
    
    /* Set Message RAM Configuration */
    MCAN1_MessageRAMConfigSet(Mcan1MessageRAM);

    MCAN1_RxFifoCallbackRegister(MCAN_RX_FIFO_0, APP_MCAN_RxFifo0Callback, APP_STATE_MCAN_RECEIVE);
    MCAN1_RxFifoCallbackRegister(MCAN_RX_FIFO_1, APP_MCAN_RxFifo1Callback, APP_STATE_MCAN_RECEIVE);
    MCAN1_RxBuffersCallbackRegister(APP_MCAN_RxBufferCallback, APP_STATE_MCAN_RECEIVE);

    display_menu();
    
    while ( true )
    {
        if (state == APP_STATE_MCAN_USER_INPUT)
        {
            /* Read user input */
            scanf("%c", (char *) &user_input);
            
            switch (user_input)
            {
				case '0':
                    memset(txFiFo, 0x00, MCAN1_TX_FIFO_BUFFER_ELEMENT_SIZE);
                    txBuffer = (MCAN_TX_BUFFER *)txFiFo;
                    txBuffer->id = WRITE_ID(0x45A);
                    txBuffer->dlc = MCANLengthToDlcGet(64);
                    txBuffer->fdf = 1;
                    txBuffer->brs = 1;
					for (loop_count = 0; loop_count < 64; loop_count++){
						txBuffer->data[loop_count] = loop_count;
					}                
					printf("  0: Send FD standard message with ID: 0x45A and 64 byte data 0 to 63.\r\n");
                    MCAN1_TxFifoCallbackRegister( APP_MCAN_TxFifoCallback, (uintptr_t)APP_STATE_MCAN_TRANSMIT );
                    state = APP_STATE_MCAN_IDLE;
                    if (MCAN1_MessageTransmitFifo(1, txBuffer) == false)
                    {
                        printf(" Failed \r\n");
                    }             
                    break;
				case '1':
                    memset(txFiFo, 0x00, MCAN1_TX_FIFO_BUFFER_ELEMENT_SIZE);
                    txBuffer = (MCAN_TX_BUFFER *)txFiFo;
                    txBuffer->id = WRITE_ID(0x469);
                    txBuffer->dlc = MCANLengthToDlcGet(64);
                    txBuffer->fdf = 1;
                    txBuffer->brs = 1;
					for (loop_count = 128; loop_count < 192; loop_count++){
						txBuffer->data[loop_count - 128] = loop_count;
					}                
 					printf("  1: Send FD standard message with ID: 0x469 and 64 byte data 128 to 191.\r\n");
					MCAN1_TxFifoCallbackRegister( APP_MCAN_TxFifoCallback, (uintptr_t)APP_STATE_MCAN_TRANSMIT );
                    state = APP_STATE_MCAN_IDLE;
					if (MCAN1_MessageTransmitFifo(1, txBuffer) == false)
                    {
                        printf(" Failed \r\n");
                    }             
                    break;
				case '2':
                    memset(txFiFo, 0x00, MCAN1_TX_FIFO_BUFFER_ELEMENT_SIZE);
                    txBuffer = (MCAN_TX_BUFFER *)txFiFo;
                    txBuffer->id = 0x100000A5;
                    txBuffer->dlc = MCANLengthToDlcGet(64);
                    txBuffer->xtd = 1;
                    txBuffer->fdf = 1;
                    txBuffer->brs = 1;
					for (loop_count = 0; loop_count < 64; loop_count++){
						txBuffer->data[loop_count] = loop_count;
					}
					printf("  2: Send FD extended message with ID: 0x100000A5 and 64 byte data 0 to 63.\r\n");
                    MCAN1_TxFifoCallbackRegister( APP_MCAN_TxFifoCallback, (uintptr_t)APP_STATE_MCAN_TRANSMIT );
                    state = APP_STATE_MCAN_IDLE;
                    if (MCAN1_MessageTransmitFifo(1, txBuffer) == false)
                    {
                        printf(" Failed \r\n");
                    }
                    break;
				case '3':
                    memset(txFiFo, 0x00, MCAN1_TX_FIFO_BUFFER_ELEMENT_SIZE);
                    txBuffer = (MCAN_TX_BUFFER *)txFiFo;
                    txBuffer->id = 0x10000096;
                    txBuffer->dlc = MCANLengthToDlcGet(64);
                    txBuffer->xtd = 1;
                    txBuffer->fdf = 1;
                    txBuffer->brs = 1;
					for (loop_count = 128; loop_count < 192; loop_count++){
						txBuffer->data[loop_count - 128] = loop_count;
					}
					printf("  3: Send FD extended message with ID: 0x10000096 and 64 byte data 128 to 191.\r\n");
                    MCAN1_TxFifoCallbackRegister( APP_MCAN_TxFifoCallback, (uintptr_t)APP_STATE_MCAN_TRANSMIT );
                    state = APP_STATE_MCAN_IDLE;
                    if (MCAN1_MessageTransmitFifo(1, txBuffer) == false)
                    {
                        printf(" Failed \r\n");
                    }
                    break;
				case '4':
                    memset(txFiFo, 0x00, MCAN1_TX_FIFO_BUFFER_ELEMENT_SIZE);
                    txBuffer = (MCAN_TX_BUFFER *)txFiFo;
					txBuffer->id = WRITE_ID(0x469);
                    txBuffer->dlc = 8;
					for (loop_count = 0; loop_count < 8; loop_count++){
						txBuffer->data[loop_count] = loop_count;
					}                
 					printf("  4: Send normal standard message with ID: 0x469 and 8 byte data 0 to 7.\r\n");
					MCAN1_TxFifoCallbackRegister( APP_MCAN_TxFifoCallback, (uintptr_t)APP_STATE_MCAN_TRANSMIT );
                    state = APP_STATE_MCAN_IDLE;
					if (MCAN1_MessageTransmitFifo(1, txBuffer) == false)
                    {
                        printf(" Failed \r\n");
                    }             
                    break;
				case 'm':
				case 'M':
					display_menu();
					break;
					
				default:
					printf(" Invalid Input \r\n");
					break;
            }
        }

        /* Check the application's current state. */
        switch (state)
        {
            case APP_STATE_MCAN_IDLE:
            {
                /* Application can do other task here */
                break;
            }
            case APP_STATE_MCAN_XFER_SUCCESSFUL:
            {
                if ((APP_STATES)xferContext == APP_STATE_MCAN_TRANSMIT)
                {
                    printf(" Success\r\n");
                }                
                state = APP_STATE_MCAN_USER_INPUT;
                break;
            }
            case APP_STATE_MCAN_XFER_ERROR:
            {
                if ((APP_STATES)xferContext == APP_STATE_MCAN_RECEIVE)
                {
                    printf(" Error in received message\r\n");
                }
                else
                {
                    printf(" Failed\r\n");
                }
                state = APP_STATE_MCAN_USER_INPUT;
                break;
            }
            default:
            {
                break;
            }
        }
    }

    /* Execution should not come here during normal operation */

    return ( EXIT_FAILURE );
}

Library Interface

Controller Area Network peripheral library provides the following interfaces:

Functions

NameDescription
MCANx_InitializeInitializes given instance of the MCAN peripheral
MCANx_MessageTransmitTransmits a message into CAN bus from the specific Tx buffer
MCANx_MessageTransmitFifoTransmit multiple messages into CAN bus from Tx FIFO
MCANx_TxFifoFreeLevelGetReturns Tx FIFO Free Level
MCANx_TxBufferIsBusyCheck if Transmission request is pending for the specific Tx buffer
MCANx_TxEventFifoReadRead Tx Event FIFO for the transmitted messages
MCANx_TxEventFifoFillLevelGetReturns Tx Event FIFO Fill Level
MCANx_MessageReceiveRead a message from the specific Rx Buffer
MCANx_RxBufferNumberGetGet Rx Buffer Number
MCANx_MessageReceiveFifoRead messages from Rx FIFO0/FIFO1
MCANx_RxFifoFillLevelGetReturns Rx FIFO0/FIFO1 Fill Level
MCANx_ErrorGetReturns the error during transfer
MCANx_ErrorCountGetReturns the transmit and receive error count during transfer
MCANx_InterruptGetReturns the Interrupt status
MCANx_InterruptClearClears Interrupt status
MCANx_MessageRAMConfigSetSet the Message RAM Configuration
MCANx_StandardFilterElementSetSet a standard filter element configuration
MCANx_StandardFilterElementGetGet a standard filter element configuration
MCANx_ExtendedFilterElementSetSet a Extended filter element configuration
MCANx_ExtendedFilterElementGetGet a Extended filter element configuration
MCANx_SleepModeEnterPuts the MCAN Peripheral in sleep mode (clock stop request)
MCANx_SleepModeExitExits MCAN peripheral from sleep mode (clock stop request)
MCANx_TxBuffersCallbackRegisterSets the pointer to the function (and it is contextHandle) to be called when the given MCAN's Tx transfer events occur
MCANx_TxFifoCallbackRegisterSets the pointer to the function (and it is contextHandle) to be called when the given MCAN's Tx transfer events occur
MCANx_TxEventFifoCallbackRegisterSets the pointer to the function (and it is contextHandle) to be called when the given MCAN's Tx transfer events occur
MCANx_RxBuffersCallbackRegisterSets the pointer to the function (and it is contextHandle) to be called when the given MCAN's Rx transfer events occur
MCANx_RxFifoCallbackRegisterSets the pointer to the function (and it is contextHandle) to be called when the given MCAN's Rx transfer events occur

Data types and constants

NameTypeDescription
MCAN_ERROR_NONEMacroMCAN Error None
MCAN_ERROR_LEC_STUFFMacroMCAN Error LEC_STUFF
MCAN_ERROR_LEC_ACKMacroMCAN Error LEC_ACK
MCAN_ERROR_LEC_BIT1MacroMCAN Error LEC_BIT1
MCAN_ERROR_LEC_BIT0MacroMCAN Error LEC_BIT0
MCAN_ERROR_LEC_FORMMacroMCAN Error LEC_FORM
MCAN_ERROR_LEC_CRCMacroMCAN Error LEC_CRC
MCAN_ERROR_LEC_NO_CHANGEMacroMCAN Error LEC_NO_CHANGE
MCAN_ERROR_WARNING_STATUSMacroMCAN Error WARNING_STATUS
MCAN_ERROR_PASSIVEMacroMCAN Error PASSIVE
MCAN_ERROR_BUS_OFFMacroMCAN Error BUS_OFF
MCAN_ERROR_DLEC_STUFFMacroMCAN Error DLEC_STUFF
MCAN_ERROR_DLEC_ACKMacroMCAN Error DLEC_ACK
MCAN_ERROR_DLEC_BIT1MacroMCAN Error DLEC_BIT1
MCAN_ERROR_DLEC_BIT0MacroMCAN Error DLEC_BIT0
MCAN_ERROR_DLEC_FORMMacroMCAN Error DLEC_FORM
MCAN_ERROR_DLEC_CRCMacroMCAN Error DLEC_CRC
MCAN_ERROR_DLEC_NO_CHANGEMacroMCAN Error DLEC_NO_CHANGE
MCAN_ERROR_PROTOCOL_EXCEPTION_EVENTMacroMCAN Error PROTOCOL_EXCEPTION_EVENT
MCAN_ERROR_INVALIDMacroMCAN Error Invalid
MCAN_RX_FIFO_NUMEnumMCAN Rx FIFO Number
MCAN_INTERRUPT_MASKEnumMCAN Interrupt Mask
MCAN_ERRORTypedefMCAN Transfer Error data type
MCAN_TX_FIFO_CALLBACKTypedefMCAN Callback Function Pointer for Tx FIFO
MCAN_TXRX_BUFFERS_CALLBACKTypedefMCAN Callback Function Pointer for TX/RX Buffers
MCAN_TX_EVENT_FIFO_CALLBACKTypedefMCAN Callback Function Pointer for Tx Event FIFO
MCAN_RX_FIFO_CALLBACKTypedefMCAN Callback Function Pointer for Rx FIFO0/FIFO1
MCAN_MSG_RAM_CONFIGStructMCAN Message RAM Configuration structure
MCAN_RX_BUFFERStructMCAN Rx Buffer and FIFO Element Structure
MCAN_TX_BUFFERStructMCAN Tx Buffer Element Structure
MCAN_TX_EVENT_FIFOStructMCAN Tx Event FIFO Element Structure
MCAN_TX_FIFO_CALLBACK_OBJStructMCAN transfer event callback structure for Tx FIFO
MCAN_TXRX_BUFFERS_CALLBACK_OBJStructMCAN transfer event callback structure for Tx/Rx Buffers
MCAN_TX_EVENT_FIFO_CALLBACK_OBJStructMCAN transfer event callback structure for Tx Event FIFO
MCAN_RX_FIFO_CALLBACK_OBJStructMCAN transfer event callback structure for Rx FIFO0/FIFO1
Note: Not all APIs maybe implemented. See the specific device family section for available APIs.