This document describes the implementation of the port CANopen driver on a generic CAN abstraction layer. The aim is to simplify the porting of the CANopen driver to any underlaying CAN-HW. The new CANopen driver “Generic-CANHAL” is based on this generic CAN abstraction layer.

 

This new CAN abstraction layer consists of two parts. The first layer (CANHAL) includes the generic API function and the second layer consists of the target-specific implementation (target adaptation).

There is an available target adaption with the STM32H743x and example projects for the IDE Atollic TrueSTUDIO (based on GCC).

General layers model:

 

Application / Example

port CANopen Library

Vendor HAL-Layer

CAN-HW /Controller

port CANopen Driver - Generic-CANHAL

CANHAL

CAN Target Adaption

 

 

Vendor HAL-Layer

CAN-HW /Controller

 

 Notes to the layers:

 

Layer name

Who takes care of the implementation

Description

Application/

Example

Customer

User application

The delivery from port includes several example applications (e.g. s1, s2).

 

port CANopen Library

Separate delivery from port

(source folder: canopen)

 

HW independent CANopen Library from port

port CANopenDriver /

Generic-CANHAL

Delivery from port

(source folders:

“drivers/co_generic”,

”drivers/shar_src”,

“drivers/shar_inc”)

General connection layer between CANopen Library and target based on the CAN abstraction layer

This layer includes the usual driver API for a CANopen application additionally with necessary CPU/board initializations.

 

port CANopenDriver /

CANHAL

Delivery from port

(sources: “drivers/canhal/canhal.[c,h]”)

Generic fixed CAN API called by the new CANopen Generic driver.

port CANopenDriver /

 

CAN Target Adaption

Customer

(port provides the API functions as template).

Delivery from port

(sources: “drivers/canhal/cantarget.[c,h]”)

 

Specific implementation of the API for the target.

The code contains additional "Todo’s" to help.

Vendor HAL-Layer

Supplier of the HAL-Layer, normally the CPU- manufacturer

The Vendor HAL-Layer allows the access to the CAN controller via HAL-Layer functions, e.g. STM32CubeH7 - HAL-layer.

But it is also possible to access directly to the CAN controller registers without Vendor HAL-Layer.

CAN-HW /Controller

HW (CPU, CAN-interface manufacturer)

Possible are also external CAN interfaces.

 

 

 

Supported features with the current CAN abstraction layer implementing:

but not yet implemented in the available target adaption (STM32H7xx)

 

 

 

 

 

 

 

Folder sructure of driver package “Generic-CANHAL” :

The delivery consists of two parts. The first part contains all the generic driver sources without HW access.

The second part is our porting  to the STM32H7xx target with realy HW access, in particular also to the CAN abstraction layer.

Part1: 0565_178_CO_DP_Generic_CANHAL_Driver_1_xx.zip                                      (xx = version string)

Part2: 0565_178_CO_DP_Generic_CANHAL_Driver_2_xx.zip

If both *.zip archives are unpacked in the same directory, the following structure is created.

Folder structure with comments (sources of the second delivery part marked here in blue):

--- |-- canopen                                                             (CANopen Library, not part from this driver deliverys)

     |

     |-- drivers

     |         |

     |         |-- co_generic                                            (CPU/Board adaption folder (not CAN), in generic without HW-access)

     |         |-- co_stm32H7xx                                    (CPU/Board adaption folder (not CAN), with STM32H7xx HW-access)

     |         |

     |         |-- co_canhal

     |         |             |-- co_canhal.c,.h                                 (CAN abstraction layer API - CANHAL)

     |         |              |-- co_cantarget.c,.h                            (CAN abstraction layer API – target adaption template)

     |         |              |-- co_cantartget_stm32h7xx.c,.h   (CAN abstraction layer API – target adaption on STM32H743x)

     |         |                                                                            

     |         |-- shar_inc                                                          (shared driver includes)

     |         |              |-- can_generic_canhal.h                    (internal access to the CAN abstraction layer API)

     |         |              |-- cpu_generic.h

     |         |              |-- …                      

     |         |              |-- cpu_stm32_h7.h                           (CPU porting to STM32H7xx)

     |         |

     |         |-- shar_src                                                           (shared driver sources, especially timer service part)

     |                        |-- can_generic_canhal.c                    (internal access to the CAN abstraction layer API)

     |                        |-- cpu_generic.c

     |                        |-- …

     |                        |-- cpu_stm32_h7.c                            (CPU porting to STM32H7xx)

     |        

--- |-- examples                                                                    (example projects generated by the IDE Atollic TrueSTUDIO)

                |-- s1_canhal_generic                                       (generic slave single-line example)

                |-- s4_canhal_generic                                       (generic slave multi-line example)

|-- s1_canhal_stm32H7xx                                (slave single-line example ported on STM32H7xx)

|-- s2_canhal_stm32H7xx                                (slave single-line example ported on STM32H7xx)

|-- s3_canhal_stm32H7xx                                (slave single-line example ported on STM32H7xx)

|-- m1_canhal_stm32H7xx                              (master single-line example ported on STM32H7xx)

                |-- s4_canhal_stm32H7xx                                (slave single-line example ported on STM32H7xx)

 

 

 

If the customer wants to develop his own driver, he can use the generic sources as a template. The sources marked in blue for the STM32H7xx can used as a reference for the own development. These must be adapted or created for a new target.

 

 Short API description of the target adaptation layer functions to be implemented:

(file cantarget.[c,.h]):

 

/****************************************************************************/

/* prototypes */

/****************************************************************************/

 

/****************************************************************************/

/** Initialize target CAN board peripherals

 *

 *

 */

RET_T coCAN_targetCanBoardInit(

    void

);

 

 

/****************************************************************************/

/** Initialize CAN peripherals

 *

 *

 */

RET_T coCAN_targetCanInit(

    UNSIGNED8 canLine                /**< [in] number of CAN line */

);

 

 

/****************************************************************************/

/** Get CAN filter max.

 *

 *

 */

UNSIGNED32 coCAN_targetCanGetFilterMax(

    UNSIGNED8 canLine                    /**< [in] number of CAN line */

);

 

 

 

/****************************************************************************/

/** Start CAN interface

 *

 *

 */

RET_T coCAN_targetCanStart(

    UNSIGNED8 canLine              /**< [in] number of CAN line */

);

 

 

/****************************************************************************/

/** Stop CAN interface

 *

 *

 */

RET_T coCAN_targetCanStop(

    UNSIGNED8 canLine            /**< [in] number of CAN line */

);

 

 

/****************************************************************************/

/** CAN target driver set receive filter

 *

 *

 */

RET_T coCAN_targetCanSetFilter(

    UNSIGNED8 canLine,               /**< [in] number of CAN line */

    CO_CAN_FILTER_T filter           /**< [in] filter struct */

);

 

 

/****************************************************************************/

/** Set bitrate to CAN peripheries

 *

bit rate in the target CAN.

 *

 */

RET_T coCAN_targetCanSetBitrate(

    UNSIGNED8 canLine,              /**< [in] number of CAN line */

    UNSIGNED32 bitrateindex       /**< [in] index for the desired CAN bit rate

                                       from bit timing table 0 according to CiA-305 */

);

 

 

/****************************************************************************/

/** CAN driver send

 *

 *

 */

RET_T coCAN_targetCanSend(

    UNSIGNED8 canLine,               /**< [in] number of CAN line */

    CO_CANHAL_MSG_T *p_can_msg       /**< [in] CAN message for transmission */

);

 

 

/****************************************************************************/

/** CAN target driver interrupt handler

 *

 *

 */

void coCAN_targetCanInterrupt(

    UNSIGNED8 canLine                    /**< [in] number of CAN line */

);

 

The received data or status events received in the interrupt handler must be transferred to the CANHAL via the following callback:

 

/* prototype for the callback function of CANHAL layer,

void coCANHAL_targetCanDriverCallback(

    UNSIGNED8 canLine,          /**< [in] number of CAN line */

    CO_CAN_EVENT_T event,       /**< [in] trigger event for interrupt */

    CO_CANHAL_MSG_T *pData);    /**< [in] received data */

   

 

Some examples for calling the callback functions:

 

/* callback function to upper layer with receive message data */

coCANHAL_targetCanDriverCallback(canLine, CO_CAN_EVENT_RX, &can_msg);

/* callback function to upper layer, TX message done */

coCANHAL_targetCanDriverCallback(canLine, CO_CAN_EVENT_TXC, NULL);

/* callback function to upper layer, ERR_PASSIV occurred */

coCANHAL_targetCanDriverCallback(canLine, CO_CAN_EVENT_ERR_PASSIVE, NULL);

/* callback function to upper layer, CAN overrun occurred */

coCANHAL_targetCanDriverCallback(canLine, CO_CAN_EVENT_ERR_OVERRUN, NULL);

 

 

 

 

Used data types and parameters for implementing the target layer API:

 

/**< CAN bit rate */

/* These index values shall be used for argument bitrateindex for function

#define CO_CAN_BAUDRATE_UNKNOWN   0xFFu

#define CO_CAN_BAUDRATE_10        0x00u

#define CO_CAN_BAUDRATE_20        0x01u

#define CO_CAN_BAUDRATE_50        0x02u

#define CO_CAN_BAUDRATE_100       0x03u

#define CO_CAN_BAUDRATE_125       0x04u

#define CO_CAN_BAUDRATE_250       0x05u

#define CO_CAN_BAUDRATE_500       0x06u

#define CO_CAN_BAUDRATE_800       0x07u

#define CO_CAN_BAUDRATE_1000      0x08u

 

#define CO_CAN_BAUDRATE_INDEX    CO_CAN_BAUDRATE_125   /* default used 125 kbit/s */

 

/****************************************************************************/

/* enums */

/****************************************************************************/

/**< CAN event */

typedef enum {

    CO_CAN_EVENT_RX = 0,                        /**< message received */

    CO_CAN_EVENT_TXC,                           /**< message transmitted */

    CO_CAN_EVENT_ERR_BUSOFF,                    /**< bus is off */

    CO_CAN_EVENT_ERR_PASSIVE,                   /**< no acknowledge */

    CO_CAN_EVENT_ERR_ACTIVE,                    /**< bus ok */

    CO_CAN_EVENT_ERR_OVERRUN                    /**< received message lost */

} CO_CAN_EVENT_T;

 

 

/****************************************************************************/

/* structures */

/****************************************************************************/

 

/**< CAN message buffer */

typedef struct {

    UNSIGNED32 messageID;                       /**< message identifier */

    BOOL_T rtrFlag;                             /**< Remote Transmission requested */

    BOOL_T extendedFlag;                        /**< extended identifier */

    UNSIGNED8 canLine;                          /**< number of line */

    UNSIGNED8 dataLen;                          /**< length of data in byte */

    UNSIGNED8 data[CO_CAN_DATA_LEN];            /**< message data */

} CO_CANHAL_MSG_T;

 

/**< CAN Filter type */

typedef struct {

    UNSIGNED32 messageID;             /**< filtered message identifier */

    BOOL_T rtrFlag;                   /**< filter RTR frames */

    BOOL_T extendedFlag;              /**< filter frames with extended identifier */

    UNSIGNED8 canLine;                /**< number of CAN line */

} CO_CAN_FILTER_T;