Skip to content

Commit

Permalink
Merge pull request #137 from RICCIARDI-Adrien/add_canfd_support
Browse files Browse the repository at this point in the history
Add CAN-FD support to the CAN stack
  • Loading branch information
RICCIARDI-Adrien authored Oct 19, 2023
2 parents f9bad71 + 9953a05 commit c662408
Show file tree
Hide file tree
Showing 7 changed files with 396 additions and 117 deletions.
137 changes: 116 additions & 21 deletions examples/posix/can_demo/can_demo.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
/**
* @file can_demo.c
*
* @section desc File description
*
* Test most of the CAN and CAN-FD stack functions using the POSIX virtual
* environment and a stub driver.
*
* @section copyright Copyright
*
* Trampoline OS
*
* Trampoline is copyright (c) IRCCyN 2005+
* Trampoline is protected by the French intellectual property law.
*
* (C) BayLibre 2023
*
* This software is distributed under the Lesser GNU Public Licence
*
* @section infos File informations
*
* $Date$
* $Rev$
* $Author$
* $URL$
*/
#include <Can.h>
#include <CanIf.h>
#include <stdio.h>
Expand All @@ -7,16 +33,49 @@

int main(void)
{
// Statically list the CAN controllers to use in the application
static tpl_can_controller_t *can_controllers[] =
// Statically list the configuration of each CAN controller used in the application
static tpl_can_controller_config_t can_controllers_config[] =
{
&can_demo_driver_controller_1,
&can_demo_driver_controller_2,
NULL
// First controller will use CAN 2.0 (values are fake)
{
&can_demo_driver_controller_1,
{
.CanControllerBaudRate = 250,
.CanControllerBaudRateConfigID = 0,
.CanControllerPropSeg = 0,
.CanControllerSeg1 = 11,
.CanControllerSeg2 = 4,
.CanControllerSyncJumpWidth = 4,
.use_fd_configuration = FALSE
},
},
// Second controller will use CAN FD with bit rate switch (values are fake)
{
&can_demo_driver_controller_2,
{
.CanControllerBaudRate = 1000,
.CanControllerBaudRateConfigID = 1,
.CanControllerPropSeg = 0,
.CanControllerSeg1 = 31,
.CanControllerSeg2 = 8,
.CanControllerSyncJumpWidth = 8,
.use_fd_configuration = TRUE,
{
.CanControllerFdBaudRate = 5000,
.CanControllerPropSeg = 0,
.CanControllerSeg1 = 10,
.CanControllerSeg2 = 5,
.CanControllerSspOffset = 15,
.CanControllerSyncJumpWidth = 5,
.CanControllerTxBitRateSwitch = TRUE
},
},
}
};
static Can_ConfigType can_config_type =
{
can_controllers
can_controllers_config,
sizeof(can_controllers_config) / sizeof(can_controllers_config[0])
};
int ret;

Expand All @@ -28,33 +87,21 @@ int main(void)
return -1;
}

printf("Setting first controller baud rate...\r\n");
ret = CanIf_SetBaudrate(0, CAN_BAUD_RATE_500_KBPS);
if (ret)
{
printf("[%s:%d] Error : CanIf_SetBaudrate() failed (%d).\r\n", __func__, __LINE__, ret);
return -1;
}

StartOS(OSDEFAULTAPPMODE);
return 0;
}

TASK(can_task)
{
Std_ReturnType ret;
uint8 payload[8];
uint8 payload[64];
Can_PduType can_pdu, *pointer_can_pdu;
PduInfoType pdu_info;
int i;

printf("Transmitting a CAN 2.0 frame with standard ID...\r\n");
can_pdu.id = 0x123 | TPL_CAN_ID_TYPE_STANDARD;
strcpy((char *) payload, "Ciao !");
can_pdu.length = strlen((char *) payload);
can_pdu.sdu = payload;
pdu_info.SduDataPtr = (uint8 *) &can_pdu;
pdu_info.SduLength = sizeof(can_pdu);
tpl_can_fill_pdu_info(&can_pdu, &pdu_info, 0x123 | TPL_CAN_ID_TYPE_STANDARD, payload, strlen((char *) payload));
ret = CanIf_Transmit(0, &pdu_info);
if (ret)
printf("[%s:%d] Error : failed to transmit the frame (%d).\r\n", __func__, __LINE__, ret);
Expand All @@ -69,11 +116,59 @@ TASK(can_task)
printf("A frame has been received.\r\n");

pointer_can_pdu = (Can_PduType *) pdu_info.SduDataPtr;
printf("ID = 0x%X, length = %d, payload = ", pointer_can_pdu->id, pointer_can_pdu->length);
printf("ID = 0x%X, flags = 0x%02X, length = %d, payload = ",
pointer_can_pdu->id & TPL_CAN_ID_STANDARD_MASK,
TPL_CAN_ID_TYPE_GET(pointer_can_pdu->id),
pointer_can_pdu->length);
for (i = 0; i < pointer_can_pdu->length; i++)
printf("0x%02X ", pointer_can_pdu->sdu[i]);
printf("\r\n");
}

printf("Transmitting a CAN-FD frame with extended ID...\r\n");
strcpy((char *) payload, "This is a longer string.");
tpl_can_fill_pdu_info(&can_pdu, &pdu_info, 0xABCD123 | TPL_CAN_ID_TYPE_FD_EXTENDED, payload, strlen((char *) payload)); // The FD length will be automatically adapted by the driver
ret = CanIf_Transmit(1, &pdu_info);
if (ret)
printf("[%s:%d] Error : failed to transmit the frame (%d).\r\n", __func__, __LINE__, ret);
printf("Transmission succeeded.\r\n");

printf("Waiting for a CAN-FD frame with extended ID...\r\n");
ret = CanIf_ReadRxPduData(1, &pdu_info);
if (ret)
printf("No frame is available.\r\n");
else
{
printf("A frame has been received.\r\n");

pointer_can_pdu = (Can_PduType *) pdu_info.SduDataPtr;
printf("ID = 0x%X, flags = 0x%02X, length = %d, payload = ",
pointer_can_pdu->id & TPL_CAN_ID_EXTENDED_MASK,
TPL_CAN_ID_TYPE_GET(pointer_can_pdu->id),
pointer_can_pdu->length);
for (i = 0; i < pointer_can_pdu->length; i++)
printf("0x%02X ", pointer_can_pdu->sdu[i]);
printf("\r\n");
}

printf("Setting the controller 0 baud rate with configuration 1...\r\n");
ret = CanIf_SetBaudrate(0, 1);
if (ret)
printf("[%s:%d] Error : CanIf_SetBaudrate() failed (%d).\r\n", __func__, __LINE__, ret);

printf("Setting the controller 1 baud rate with configuration 0...\r\n");
ret = CanIf_SetBaudrate(1, 0);
if (ret)
printf("[%s:%d] Error : CanIf_SetBaudrate() failed (%d).\r\n", __func__, __LINE__, ret);

printf("Setting an invalid baud rate configuration for controller 1...\r\n");
ret = CanIf_SetBaudrate(1, 100);
if (ret)
printf("[%s:%d] The baud rate configuration setting failed as expected.\r\n", __func__, __LINE__);
else
printf("[%s:%d] Error : CanIf_SetBaudrate() succeeded while it should have not (%d).\r\n", __func__, __LINE__, ret);

printf("\r\nEnd of the CAN demo. Press 'q' to exit.\r\n");

TerminateTask();
}
3 changes: 2 additions & 1 deletion examples/posix/can_demo/can_demo.oil
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
OIL_VERSION = "2.5";
OIL_VERSION = "4.2";

CPU can_task {
OS config {
STATUS = EXTENDED;
BUILD = TRUE {
APP_SRC = "can_demo.c";
TRAMPOLINE_BASE_PATH = "../../..";
CFLAGS = "-W -Wall";
LDFLAGS = "-lrt -lpthread";
APP_NAME = "can_demo_exe";
LINKER = "gcc";
Expand Down
98 changes: 60 additions & 38 deletions machines/posix/tpl_can_demo_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,30 @@
#include <stdio.h>
#include <string.h>
#include <tpl_can_demo_driver.h>
#include <tpl_os.h>

static int can_demo_driver_init(struct tpl_can_controller_t *ctrl, void *data);
static int can_demo_driver_set_baudrate(struct tpl_can_controller_t *ctrl, tpl_can_baud_rate_t baud_rate);
static int can_demo_driver_init(struct tpl_can_controller_config_t *config);
static int can_demo_driver_set_baudrate(struct tpl_can_controller_t *ctrl, CanControllerBaudrateConfig *baud_rate_config);
static Std_ReturnType can_demo_driver_transmit(struct tpl_can_controller_t *ctrl, const Can_PduType *pdu_info);
static Std_ReturnType can_demo_driver_receive(struct tpl_can_controller_t *ctrl, Can_PduType *pdu_info);
static int can_demo_driver_is_data_available(struct tpl_can_controller_t *ctrl);

struct can_demo_driver_priv
{
int is_can_fd_enabled;
};

static struct can_demo_driver_priv can_demo_driver_controller_priv[2];

tpl_can_controller_t can_demo_driver_controller_1 =
{
0x12341111,
can_demo_driver_init,
can_demo_driver_set_baudrate,
can_demo_driver_transmit,
can_demo_driver_receive,
can_demo_driver_is_data_available
can_demo_driver_is_data_available,
&can_demo_driver_controller_priv[0]
};

tpl_can_controller_t can_demo_driver_controller_2 =
Expand All @@ -51,44 +60,44 @@ tpl_can_controller_t can_demo_driver_controller_2 =
can_demo_driver_set_baudrate,
can_demo_driver_transmit,
can_demo_driver_receive,
can_demo_driver_is_data_available
can_demo_driver_is_data_available,
&can_demo_driver_controller_priv[1]
};

static int can_demo_driver_init(struct tpl_can_controller_t *ctrl, void *data)
static int can_demo_driver_init(struct tpl_can_controller_config_t *config)
{
(void) data;
struct can_demo_driver_priv *priv = config->controller->priv;

printf("[%s:%d] Initialized controller 0x%08X.\r\n", __func__, __LINE__, ctrl->base_address);
// Determine the CAN protocol version
if (config->baud_rate_config.use_fd_configuration)
priv->is_can_fd_enabled = 1;
else
priv->is_can_fd_enabled = 0;

printf("[%s:%d] Initializing controller 0x%08X...\r\n",
__func__,
__LINE__,
config->controller->base_address);
printf("Protocol version : %s\r\nNominal baud rate : %u kbps\r\n",
priv->is_can_fd_enabled ? "CAN-FD" : "CAN classic 2.0",
config->baud_rate_config.CanControllerBaudRate);
if (priv->is_can_fd_enabled)
printf("Data baud rate (only for CAN-FD) : %u kbps\r\n", config->baud_rate_config.can_fd_config.CanControllerFdBaudRate);
return 0;
}

static int can_demo_driver_set_baudrate(struct tpl_can_controller_t *ctrl, tpl_can_baud_rate_t baud_rate)
static int can_demo_driver_set_baudrate(struct tpl_can_controller_t *ctrl, CanControllerBaudrateConfig *baud_rate_config)
{
static uint32 baud_rate_lut[] =
{
// CAN_BAUD_RATE_50_KBPS
50000,
// CAN_BAUD_RATE_100_KBPS
100000,
// CAN_BAUD_RATE_125_KBPS
125000,
// CAN_BAUD_RATE_250_KBPS
250000,
// CAN_BAUD_RATE_500_KBPS
500000,
// CAN_BAUD_RATE_1_MBPS
1000000
};
uint32 bits_per_second;

if (baud_rate >= CAN_BAUD_RATE_COUNT)
{
printf("[%s:%d] Wrong baud rate code %d, aborting.\r\n", __func__, __LINE__, baud_rate);
return -1;
}
bits_per_second = baud_rate_lut[baud_rate];
printf("[%s:%d] Setting a new baud rate for controller 0x%08X. Protocol version : %s, nominal baud rate : %u kbps",
__func__,
__LINE__,
ctrl->base_address,
baud_rate_config->use_fd_configuration ? "CAN-FD" : "CAN classic 2.0",
baud_rate_config->CanControllerBaudRate);
if (baud_rate_config->use_fd_configuration)
printf(", CAN-FD data baud rate : %u kbps", baud_rate_config->can_fd_config.CanControllerFdBaudRate);
printf(".\r\n");

printf("[%s:%d] Baud rate set to %u for controller 0x%08X.\r\n", __func__, __LINE__, bits_per_second, ctrl->base_address);
return 0;
}

Expand All @@ -97,7 +106,12 @@ static Std_ReturnType can_demo_driver_transmit(struct tpl_can_controller_t *ctrl
uint32 i;

printf("[%s:%d] Transmission request for controller 0x%08X, CAN ID = 0x%X, flags = 0x%02X, payload length = %u, payload = ",
__func__, __LINE__, ctrl->base_address, pdu_info->id & ~TPL_CAN_ID_TYPE_MASK, pdu_info->length, pdu_info->id >> 30);
__func__,
__LINE__,
ctrl->base_address,
pdu_info->id & TPL_CAN_ID_EXTENDED_MASK,
TPL_CAN_ID_TYPE_GET(pdu_info->id),
pdu_info->length);
for (i = 0; i < pdu_info->length; i++)
printf("0x%02X ", pdu_info->sdu[i]);
printf("\r\n");
Expand All @@ -107,12 +121,20 @@ static Std_ReturnType can_demo_driver_transmit(struct tpl_can_controller_t *ctrl

static Std_ReturnType can_demo_driver_receive(struct tpl_can_controller_t *ctrl, Can_PduType *pdu_info)
{
(void) ctrl;
if (ctrl->base_address == can_demo_driver_controller_1.base_address)
{
pdu_info->id = 0x1ab | TPL_CAN_ID_TYPE_STANDARD; // Random value
strcpy((char *) pdu_info->sdu, "Test");
pdu_info->length = strlen((char *) pdu_info->sdu);
}
else if (ctrl->base_address == can_demo_driver_controller_2.base_address)
{
pdu_info->id = 0xcafeb0b | TPL_CAN_ID_TYPE_FD_EXTENDED; // Random value
strcpy((char *) pdu_info->sdu, "The CAN-FD frame longer payload.");
pdu_info->length = strlen((char *) pdu_info->sdu);
}

pdu_info->id = 0x1ab; // Random value
strcpy((char *) pdu_info->sdu, "Test");
pdu_info->length = strlen((char *) pdu_info->sdu);
return 0;
return E_OK;
}

static int can_demo_driver_is_data_available(struct tpl_can_controller_t *ctrl)
Expand Down
29 changes: 28 additions & 1 deletion net/can/Can.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
*/
typedef struct
{
tpl_can_controller_t **controllers_list;
tpl_can_controller_config_t *configs;
unsigned int configs_count;
} Can_ConfigType;

/**
Expand Down Expand Up @@ -88,4 +89,30 @@ Std_ReturnType Can_SetBaudrate(uint8 Controller, uint16 BaudRateConfigID);
*/
Std_ReturnType Can_Write(Can_HwHandleType Hth, const Can_PduType *PduInfo);

/**
* Convert a CAN-FD payload size in bytes to the corresponding CAN Data Length
* Code.
*
* @param length The payload length in bytes.
* @param adjusted_length If not NULL, contain on output the payload adjusted
* length in bytes.
*
* @retval 0 if the provided payload length exceeds 64 bytes,
* @return The DLC code if the provided payload length is valid.
*
* @note See https://www.can-cia.org/can-knowledge/can/can-fd for more details.
*/
uint32 tpl_can_get_dlc_from_length(uint32 length, uint32 *adjusted_length);

/**
* Convert a CAN or CAN-FD DLC code to the corresponding payload length in
* bytes.
*
* @param dlc The CAN or CAN-FD frame DLC field value.
*
* @retval 0 if the provided DLC value exceeds 0x0F,
* @return The payload length in bytes if the provided DLC value is valid.
*/
uint32 tpl_can_get_length_from_dlc(uint32 dlc);

#endif
Loading

0 comments on commit c662408

Please sign in to comment.