CAT2 Peripheral Driver Library
CAN (Controller Area Network)

The CAN driver provides an easy method to access the CAN IP block registers and provides simple functionality for sending and receiving data between devices in the CAN network. More...

Modules

 Macros
 This section describes the CAN Macros.
 
 Functions
 
 Data Structures
 
 Enumerated Types
 

Detailed Description

The CAN driver provides an easy method to access the CAN IP block registers and provides simple functionality for sending and receiving data between devices in the CAN network.

The CAN driver provides an API to configure the main features - bit time, message buffers - and transmit and receive the CAN message. The CAN driver is not compatible with CAN FD or future versions.

can_solution.png
CAN Solution

Configuration Considerations

Specification of the sample code is as follows:

Use ModusToolbox Device Configurator Tool to generate initialization code

The steps to generate initialization code using the ModusToolbox Device Configurator Tool:

  1. Launch the ModusToolbox Device Configurator Tool.
  2. Switch to the Peripherals tab. Enable the CAN channel personality under Communication and enter Alias (default is can_0).
  3. Go to the Parameters Pane for the CAN Personality and configure it with the desired parameters (set the Clock Signal divider, set the bit timing configuration, set the other parameters per Configuration Considerations, etc).
  4. Perform File->Save for the initialization code to generate.

Now, all required CAN initialization code and configuration prerequisites will be generated:

For the CAN interrupt service routine, Cy_CAN_IrqHandler() can be used. It handles reading data from Rx buffers. Corresponding callback functions are called for error interrupts, Rx interrupts and Tx complete interrupt. Put the names of callback functions to the Callback functions parameters section. Put NULL if no callback function to be used.

Note
Only Tx and Rx interrupt sources are enabled by default. Use Cy_CAN_SetInterruptMask() to enable other interrupt sources.
Interrupt flags are set regardless of the interrupt enable register. Cy_CAN_IrqHandler will check and process all supported interrupts when triggered with any enabled interrupt source.
/* CAN interrupt handler */
void CAN_InterruptHandler(void)
{
/* Just call the IRQ handler with the context */
Cy_CAN_IrqHandler(CAN, &context);
}

Set up the interrupt handler to be called with CAN events. The following code shows how to set up the interrupt handler:

/* Setup the CAN interrupt */
{
/* Populate the configuration structure */
const cy_stc_sysint_t irq_cfg =
{
/* .intrSrc */ can_interrupt_can_IRQn, /* CAN interrupt number */
/* .intrPriority */ 3UL
};
/* Hook the interrupt service routine and enable the interrupt */
(void) Cy_SysInt_Init(&irq_cfg, &CAN_InterruptHandler);
NVIC_EnableIRQ(can_interrupt_can_IRQn);
}

Implement the initialization code manually

Call Cy_CAN_Init() to initialize the CAN module. It initializes the CAN module with the configuration parameters, passed in the cy_stc_can_config_t structure. It consists of several elements to be defined first.

const cy_stc_can_config_t canConfig =
{
/* .txCallback */ NULL,
/* .rxCallback */ CAN_RxMsgCallback,
/* .errorCallback */ NULL,
/* .arbiter */ CY_CAN_FIXED_PRIORITY,
/* .swapEndian */ CY_CAN_LITTLE_ENDIAN,
/* .busOffRestart */ CY_CAN_MANUAL,
/* .bitrate */ &bitrateConfig,
/* .rxBuffer */ &(rxbConfig[0]),
/* .numOfRxBuffers */ 4u
};

The Cy_CAN_Init() function also initializes the shared context structure used later with other API functions.

cy_stc_can_context_t context; /* This is a shared context structure,
* unique for each channel
*/

Although the callback functions are optional, they are recommended for use, otherwise, there is no report to the API about any error and transmission or reception events. The example callback function sends received data back to the bus, incrementing ID by 1:

/* CAN reception callback */
void CAN_RxMsgCallback(uint8_t index,
{
CY_UNUSED_PARAMETER(index);
if (!rxMsg->rtr) /* Only for data frames */
{
/* Sends the same message back with an incremented ID */
txMsg.id += 1u;
Cy_CAN_Transmit(CAN, 0u, &txMsg, true, false, &context);
}
}

The CAN block uses the Port 4 or 6 pins for receive (P4[0],P6[1]) and transmit (P4[1],P6[2]).

/* Assign pins for CAN Rx and Tx: P6[1] and P6[2]. */
#define CAN_PORT (P6_0_PORT)
#define CAN_RX_NUM (P6_1_NUM)
#define CAN_TX_NUM (P6_2_NUM)
Cy_GPIO_SetHSIOM(CAN_PORT, CAN_RX_NUM, P6_1_CAN_CAN_RX);
Cy_GPIO_SetHSIOM(CAN_PORT, CAN_TX_NUM, P6_2_CAN_CAN_TX);
Cy_GPIO_SetDrivemode(CAN_PORT, CAN_RX_NUM, CY_GPIO_DM_HIGHZ);
Cy_GPIO_SetDrivemode(CAN_PORT, CAN_TX_NUM, CY_GPIO_DM_STRONG);

For the CAN interrupt service routine, the Cy_CAN_IrqHandler() can be used. It handles reading data from Rx buffers. Corresponding callback functions are called for error interrupts, Rx interrupts and Tx complete interrupt.

Note
Only Tx and Rx interrupt sources are enabled by default. Use Cy_CAN_SetInterruptMask() to enable other interrupt sources.
Interrupt flags are set regardless of the interrupt enable register. Cy_CAN_IrqHandler will check and process all supported interrupts when triggered with any enabled interrupt source.
/* CAN interrupt handler */
void CAN_InterruptHandler(void)
{
/* Just call the IRQ handler with the context */
Cy_CAN_IrqHandler(CAN, &context);
}

Setup the interrupt handler to be called with the CAN events. The following code shows how to set up the interrupt handler:

/* Setup the CAN interrupt */
{
/* Populate the configuration structure */
const cy_stc_sysint_t irq_cfg =
{
/* .intrSrc */ can_interrupt_can_IRQn, /* CAN interrupt number */
/* .intrPriority */ 3UL
};
/* Hook the interrupt service routine and enable the interrupt */
(void) Cy_SysInt_Init(&irq_cfg, &CAN_InterruptHandler);
NVIC_EnableIRQ(can_interrupt_can_IRQn);
}

The CAN has a bit rate setting. It consists of a pre-scaler, time segment 1, time segment 2 and synchronization jump width.

Note
The actual interpretation by the hardware of configured values is one more value than programmed.

The CAN time quantum (tq) may be programmed in the range of 1 to 32768 CAN clock periods: tq = (prescaler + 1) * Tsys, where Tsys is System Clock clock period. The length of the bit time is (programmed values) [timeSegment1 + timeSegment2 + 3] tq. The example below shows the configuration with the 250 kbps bit rate. This assumes the SYSCLK frequency of 48 MHz for the CAN block.

const cy_stc_can_bitrate_t bitrateConfig =
{
/* .prescaler */ 12u - 1u, /* can_clk = 48MHz / 12 = 4MHz
* CAN baudrate = can_clk / bit-time
* = 4MHz / 16TQ = 250Kbps */
/* .timeSegment1 */ 10u - 1u,
/* .timeSegment2 */ 5u - 1u,
/* .syncJumpWidth */ 2u - 1u,
/* .samplingMode */ CY_CAN_SAMPLING_MODE_1,
/* .edgeMode */ CY_CAN_EDGE_R_TO_D
};

CAN driver provides API to setup Message ID filtering. One filter can be set for one Rx buffer. The desired count of the filters(buffers) is specified in the cy_stc_can_config_t structure and is set once during block initialization. It is possible to change the configured filter setting with Cy_CAN_UpdateRxBufferConfig().

#define MESSAGE_ID0 (0x00000010UL)
#define MESSAGE_ID1 (0x00000020UL)
#define MESSAGE_ID1_MASK (0x0000002FUL)
#define MESSAGE_ID2 (0x00010010UL)
#define MESSAGE_ID3 (0x00010020UL)
#define MESSAGE_ID3_MASK (0x0001002FUL)
const cy_stc_can_rx_buffer_config_t rxbConfig[4] =
{
{
/* .acceptanceMask */ {
/* .id */ 0u, /* No mask bits. Receive only the Code ID */
/* .idType */ CY_CAN_IDE_STANDARD_ID,
/* .data */ 0xFFFFu,
/* .rtr */ 0u,
/* .ide */ 0u
},
/* .acceptanceCode */ {
/* .id */ MESSAGE_ID0,
/* .idType */ CY_CAN_IDE_STANDARD_ID,
/* .data */ 0xFFFFu,
/* .rtr */ 0u,
/* .ide */ 0u
},
/* .linked */ false,
/* .interruptEnabled */ true,
/* .autoReplyRtr */ false,
/* .enable */ true
},
{
/* .acceptanceMask */ {
/* .id */ MESSAGE_ID1_MASK,
/* .idType */ CY_CAN_IDE_STANDARD_ID,
/* .data */ 0xFFFFu,
/* .rtr */ 0u,
/* .ide */ 0u
},
/* .acceptanceCode */ {
/* .id */ MESSAGE_ID1,
/* .idType */ CY_CAN_IDE_STANDARD_ID,
/* .data */ 0xFFFFu,
/* .rtr */ 0u,
/* .ide */ 0u
},
/* .linked */ false,
/* .interruptEnabled */ true,
/* .autoReplyRtr */ false,
/* .enable */ true
},
{
/* .acceptanceMask */ {
/* .id */ 0u, /* No mask bits. Receive only the Code ID */
/* .idType */ CY_CAN_IDE_EXTENDED_ID,
/* .data */ 0xFFFFu,
/* .rtr */ 0u,
/* .ide */ 0u
},
/* .acceptanceCode */ {
/* .id */ MESSAGE_ID2,
/* .idType */ CY_CAN_IDE_EXTENDED_ID,
/* .data */ 0xFFFFu,
/* .rtr */ 0u,
/* .ide */ 1u
},
/* .linked */ false,
/* .interruptEnabled */ true,
/* .autoReplyRtr */ false,
/* .enable */ true
},
{
/* .acceptanceMask */ {
/* .id */ MESSAGE_ID3_MASK,
/* .idType */ CY_CAN_IDE_EXTENDED_ID,
/* .data */ 0xFFFFu,
/* .rtr */ 0u,
/* .ide */ 0u
},
/* .acceptanceCode */ {
/* .id */ MESSAGE_ID3,
/* .idType */ CY_CAN_IDE_EXTENDED_ID,
/* .data */ 0xFFFFu,
/* .rtr */ 0u,
/* .ide */ 1u
},
/* .linked */ false,
/* .interruptEnabled */ true,
/* .autoReplyRtr */ false,
/* .enable */ true
}
};

The cy_stc_can_config_t structure is used to pass all configuration to Cy_CAN_Init() function. It is populated with pointers to other structures required and constants, defined before.

const cy_stc_can_config_t canConfig =
{
/* .txCallback */ NULL,
/* .rxCallback */ CAN_RxMsgCallback,
/* .errorCallback */ NULL,
/* .arbiter */ CY_CAN_FIXED_PRIORITY,
/* .swapEndian */ CY_CAN_LITTLE_ENDIAN,
/* .busOffRestart */ CY_CAN_MANUAL,
/* .bitrate */ &bitrateConfig,
/* .rxBuffer */ &(rxbConfig[0]),
/* .numOfRxBuffers */ 4u
};

The Cy_CAN_Init() function initializes the CAN block by writing CAN configuration registers. Cy_CAN_Init() enables the Rx interrupts for new message reception into the Rx buffers. Cy_CAN_Init() also enables the Tx interrupts for the Tx buffers successful transmission. The code example also shows the test mode configuration which can be used to enable the internal loopback mode. See cy_en_can_test_mode_t for details. Cy_CAN_Init() sets test mode configuration to CY_CAN_TEST_MODE_DISABLE. Remember to disable the echo functionality in the Rx callback when using a loopback.

if (CY_CAN_SUCCESS != Cy_CAN_Init (CAN, &canConfig, &context))
{
/* Error processing */
}
/* after initialization CAN started */
/* Sets the Test mode configuration */
/* Sets the CAN controller to start mode */

To send a CAN message, a message structure must be prepared which consists of the CAN ID , data and data length.

/* Prepares a CAN message to transmit */
{
/* .id */ 0x00000055UL,
/* .data */ { 0x44332211, 0x88776655 },
/* .length */ 8u,
/* .rtr */ false,
/* .ide */ false
};

To transmit CAN messages, the function Cy_CAN_Transmit() is used. The buffer status can be retrieved by Cy_CAN_GetTxBufferStatus(). It is possible to set a callback function which will be notified whenever a message transmission has been completed.

/* Checks that the Tx buffer to use is idle */
{
/* Sends the prepared data using Tx buffer #0 */
Cy_CAN_Transmit(CAN, 0u, &txMsg, false, false, &context);
}

More Information

For more information on the CAN peripheral, refer to the technical reference manual (TRM).

Changelog

VersionChangesReason for Change
1.0 Initial version