drivers: can: Rework can_configure API

The previous API can't change the sampling-point and only allowed
bitrates that fit the time segments.
The new API allows for shifting the sampling-point and adjusts the
number of time quantum in a bit to all more possible bitrates.
The functions to calculate the timings are moved to the can_common file.
They can be used for all drivers.

Signed-off-by: Alexander Wachter <alexander@wachter.cloud>
This commit is contained in:
Alexander Wachter 2020-04-27 18:58:05 +02:00 committed by Carles Cufí
parent caa35d1a3a
commit 8b6c1bd4b7
19 changed files with 852 additions and 162 deletions

View file

@ -24,6 +24,11 @@ config CAN_SHELL
help
Enable CAN Shell for testing.
config CAN_FD_MODE
bool
help
Enable CAN-FD compatible API
config CAN_INIT_PRIORITY
int "CAN driver init priority"
default 80

View file

@ -11,6 +11,9 @@
#include <logging/log.h>
LOG_MODULE_REGISTER(can_driver);
#define CAN_CLAMP(val, min, max) MIN(MAX(val, min), max)
#define CAN_SYNC_SEG 1
#define WORK_BUF_COUNT_IS_POWER_OF_2 !(CONFIG_CAN_WORKQ_FRAMES_BUF_CNT & \
(CONFIG_CAN_WORKQ_FRAMES_BUF_CNT - 1))
@ -143,3 +146,144 @@ int can_attach_workq(const struct device *dev, struct k_work_q *work_q,
return api->attach_isr(dev, can_work_isr_put, work, filter);
}
static int update_sampling_pnt(uint32_t ts, uint32_t sp, struct can_timing *res,
const struct can_timing *max,
const struct can_timing *min)
{
uint16_t ts1_max = max->phase_seg1 + max->prop_seg;
uint16_t ts1_min = min->phase_seg1 + min->prop_seg;
uint32_t sp_calc;
uint16_t ts1, ts2;
ts2 = ts - (ts * sp) / 1000;
ts2 = CLAMP(ts2, min->phase_seg2, max->phase_seg2);
ts1 = ts - CAN_SYNC_SEG - ts2;
if (ts1 > ts1_max) {
ts1 = ts1_max;
ts2 = ts - CAN_SYNC_SEG - ts1;
if (ts2 > max->phase_seg2) {
return -1;
}
} else if (ts1 < ts1_min) {
ts1 = ts1_min;
ts2 = ts - ts1;
if (ts2 < min->phase_seg2) {
return -1;
}
}
res->prop_seg = CAN_CLAMP(ts1 / 2, min->prop_seg, max->prop_seg);
res->phase_seg1 = ts1 - res->prop_seg;
res->phase_seg2 = ts2;
sp_calc = (CAN_SYNC_SEG + ts1 * 1000) / ts;
return sp_calc > sp ? sp_calc - sp : sp - sp_calc;
}
/* Internal function to do the actual calculation */
static int can_calc_timing_int(uint32_t core_clock, struct can_timing *res,
const struct can_timing *min,
const struct can_timing *max,
uint32_t bitrate, uint16_t sp)
{
uint32_t ts = max->prop_seg + max->phase_seg1 + max->phase_seg2 +
CAN_SYNC_SEG;
uint16_t sp_err_min = UINT16_MAX;
int sp_err;
struct can_timing tmp_res;
if (sp >= 1000 ||
(!IS_ENABLED(CONFIG_CAN_FD_MODE) && bitrate > 1000000) ||
(IS_ENABLED(CONFIG_CAN_FD_MODE) && bitrate > 8000000)) {
return -EINVAL;
}
for (int prescaler = MAX(core_clock / (ts * bitrate), 1);
prescaler <= max->prescaler; ++prescaler) {
if (core_clock % (prescaler * bitrate)) {
/* No integer ts */
continue;
}
ts = core_clock / (prescaler * bitrate);
sp_err = update_sampling_pnt(ts, sp, &tmp_res,
max, min);
if (sp_err < 0) {
/* No prop_seg, seg1, seg2 combination possible */
continue;
}
if (sp_err < sp_err_min) {
sp_err_min = sp_err;
*res = tmp_res;
res->prescaler = (uint16_t)prescaler;
if (sp_err == 0) {
/* No better result than a perfect match*/
break;
}
}
}
if (sp_err_min) {
LOG_DBG("SP error: %d 1/1000", sp_err_min);
}
return sp_err_min == UINT16_MAX ? -EINVAL : (int)sp_err_min;
}
int can_calc_timing(const struct device *dev, struct can_timing *res,
uint32_t bitrate, uint16_t sample_pnt)
{
const struct can_driver_api *api = dev->api;
uint32_t core_clock;
int ret;
ret = can_get_core_clock(dev, &core_clock);
if (ret != 0) {
return ret;
}
return can_calc_timing_int(core_clock, res, &api->timing_min,
&api->timing_max, bitrate, sample_pnt);
}
#ifdef CONFIG_CAN_FD_MODE
int can_calc_timing_data(const struct device *dev, struct can_timing *res,
uint32_t bitrate, uint16_t sample_pnt)
{
const struct can_driver_api *api = dev->api;
uint32_t core_clock;
int ret;
ret = can_get_core_clock(dev, &core_clock);
if (ret != 0) {
return ret;
}
return can_calc_timing_int(core_clock, res, &api->timing_min_data,
&api->timing_max_data, bitrate, sample_pnt);
}
#endif
int can_calc_prescaler(const struct device *dev, struct can_timing *timing,
uint32_t bitrate)
{
uint32_t ts = timing->prop_seg + timing->phase_seg1 + timing->phase_seg2 +
CAN_SYNC_SEG;
uint32_t core_clock;
int ret;
ret = can_get_core_clock(dev, &core_clock);
if (ret != 0) {
return ret;
}
timing->prescaler = core_clock / (bitrate * ts);
return core_clock % (ts * timing->prescaler);
}

View file

@ -7,18 +7,39 @@
#include <syscall_handler.h>
#include <drivers/can.h>
static inline int z_vrfy_can_configure(const struct device *dev,
enum can_mode mode,
static inline int z_vrfy_can_set_timing(const struct device *dev,
const struct can_timing *timing,
const struct can_timing *timing_data);
{
Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, set_timing));
return z_impl_can_set_timing((const struct device *)dev,
(const struct can_timing *)timing,
(const struct can_timing *)timing_data);
}
#include <syscalls/can_set_timing_mrsh.c>
static inline int z_vrfy_can_set_bitrate(const struct device *dev,
uint32_t bitrate)
{
Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, configure));
Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, set_bitrate));
return z_impl_can_configure((const struct device *)dev,
(enum can_mode)mode,
return z_impl_can_set_bitrate((const struct device *)dev,
(uint32_t)bitrate);
}
#include <syscalls/can_configure_mrsh.c>
#include <syscalls/can_set_bitrate_mrsh.c>
static inline int z_vrfy_can_get_core_clock(const struct device *dev,
uint32_t *rate)
{
Z_OOPS(Z_SYSCALL_DRIVER_CAN(dev, get_core_clock));
Z_OOPS(Z_SYSCALL_MEMORY_WRITE(rate, sizeof(rate)));
return z_impl_can_get_core_clock(dev, rate);
}
#include <syscalls/can_get_core_clock_mrsh.c>
static inline int z_vrfy_can_send(const struct device *dev,
const struct zcan_frame *msg,

View file

@ -193,17 +193,24 @@ void can_loopback_detach(const struct device *dev, int filter_id)
k_mutex_unlock(&data->mtx);
}
int can_loopback_configure(const struct device *dev, enum can_mode mode,
uint32_t bitrate)
int can_loopback_set_mode(const struct device *dev, enum can_mode mode)
{
struct can_loopback_data *data = DEV_DATA(dev);
ARG_UNUSED(bitrate);
data->loopback = mode == CAN_LOOPBACK_MODE ? 1 : 0;
return 0;
}
int can_loopback_set_timing(const struct device *dev,
const struct can_timing *timing,
const struct can_timing *timing_data)
{
ARG_UNUSED(dev);
ARG_UNUSED(timing);
ARG_UNUSED(timing_data);
return 0;
}
static enum can_state can_loopback_get_state(const struct device *dev,
struct can_bus_err_cnt *err_cnt)
{
@ -234,8 +241,16 @@ static void can_loopback_register_state_change_isr(const struct device *dev,
ARG_UNUSED(isr);
}
int can_loopback_get_core_clock(const struct device *dev, uint32_t *rate)
{
/* Return 16MHz as an realistic value for the testcases */
*rate = 16000000;
return 0;
}
static const struct can_driver_api can_api_funcs = {
.configure = can_loopback_configure,
.set_mode = can_loopback_set_mode,
.set_timing = can_loopback_set_timing,
.send = can_loopback_send,
.attach_isr = can_loopback_attach_isr,
.detach = can_loopback_detach,
@ -243,10 +258,24 @@ static const struct can_driver_api can_api_funcs = {
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
.recover = can_loopback_recover,
#endif
.register_state_change_isr = can_loopback_register_state_change_isr
.register_state_change_isr = can_loopback_register_state_change_isr,
.get_core_clock = can_loopback_get_core_clock,
.timing_min = {
.sjw = 0x1,
.prop_seg = 0x00,
.phase_seg1 = 0x01,
.phase_seg2 = 0x01,
.prescaler = 0x01
},
.timing_max = {
.sjw = 0x0F,
.prop_seg = 0x0F,
.phase_seg1 = 0x0F,
.phase_seg2 = 0x0F,
.prescaler = 0xFFFF
}
};
static int can_loopback_init(const struct device *dev)
{
struct can_loopback_data *data = DEV_DATA(dev);

View file

@ -254,7 +254,7 @@ static void mcp2515_convert_mcp2515frame_to_zcanframe(const uint8_t *source,
}
}
const int mcp2515_set_mode(const struct device *dev, uint8_t mcp2515_mode)
const int mcp2515_set_mode_int(const struct device *dev, uint8_t mcp2515_mode)
{
uint8_t canstat;
@ -290,34 +290,41 @@ static int mcp2515_get_mode(const struct device *dev, uint8_t *mode)
return 0;
}
static int mcp2515_configure(const struct device *dev, enum can_mode mode,
uint32_t bitrate)
static int mcp2515_get_core_clock(const struct device *dev, uint32_t *rate)
{
const struct mcp2515_config *dev_cfg = DEV_CFG(dev);
*rate = dev_cfg->osc_freq / 2;
return 0;
}
static int mcp2515_set_timing(const struct device *dev,
const struct can_timing *timing,
const struct can_timing *timing_data)
{
ARG_UNUSED(timing_data);
struct mcp2515_data *dev_data = DEV_DATA(dev);
int ret;
if (!timing) {
return -EINVAL;
}
/* CNF3, CNF2, CNF1, CANINTE */
uint8_t config_buf[4];
uint8_t reset_mode;
if (bitrate == 0) {
bitrate = dev_cfg->bus_speed;
}
const uint8_t bit_length = 1 + dev_cfg->tq_prop + dev_cfg->tq_bs1 +
dev_cfg->tq_bs2;
/* CNF1; SJW<7:6> | BRP<5:0> */
uint8_t brp = (dev_cfg->osc_freq / (bit_length * bitrate * 2)) - 1;
const uint8_t sjw = (dev_cfg->tq_sjw - 1) << 6;
uint8_t brp = timing->prescaler;
const uint8_t sjw = (timing->sjw - 1) << 6;
uint8_t cnf1 = sjw | brp;
/* CNF2; BTLMODE<7>|SAM<6>|PHSEG1<5:3>|PRSEG<2:0> */
const uint8_t btlmode = 1 << 7;
const uint8_t sam = 0 << 6;
const uint8_t phseg1 = (dev_cfg->tq_bs1 - 1) << 3;
const uint8_t prseg = (dev_cfg->tq_prop - 1);
const uint8_t phseg1 = (timing->phase_seg1 - 1) << 3;
const uint8_t prseg = (timing->prop_seg - 1);
const uint8_t cnf2 = btlmode | sam | phseg1 | prseg;
@ -325,7 +332,7 @@ static int mcp2515_configure(const struct device *dev, enum can_mode mode,
const uint8_t sof = 0 << 7;
const uint8_t wakfil = 0 << 6;
const uint8_t und = 0 << 3;
const uint8_t phseg2 = (dev_cfg->tq_bs2 - 1);
const uint8_t phseg2 = (timing->phase_seg2 - 1);
const uint8_t cnf3 = sof | wakfil | und | phseg2;
@ -338,26 +345,17 @@ static int mcp2515_configure(const struct device *dev, enum can_mode mode,
const uint8_t rx0_ctrl = BIT(6) | BIT(5) | BIT(2);
const uint8_t rx1_ctrl = BIT(6) | BIT(5);
__ASSERT((dev_cfg->tq_sjw >= 1) && (dev_cfg->tq_sjw <= 4),
__ASSERT((timing->sjw >= 1) && (timing->sjw <= 4),
"1 <= SJW <= 4");
__ASSERT((dev_cfg->tq_prop >= 1) && (dev_cfg->tq_prop <= 8),
__ASSERT((timing->prop_seg >= 1) && (timing->prop_seg <= 8),
"1 <= PROP <= 8");
__ASSERT((dev_cfg->tq_bs1 >= 1) && (dev_cfg->tq_bs1 <= 8),
__ASSERT((timing->phase_seg1 >= 1) && (timing->phase_seg1 <= 8),
"1 <= BS1 <= 8");
__ASSERT((dev_cfg->tq_bs2 >= 2) && (dev_cfg->tq_bs2 <= 8),
__ASSERT((timing->phase_seg2 >= 2) && (timing->phase_seg2 <= 8),
"2 <= BS2 <= 8");
__ASSERT(dev_cfg->tq_prop + dev_cfg->tq_bs1 >= dev_cfg->tq_bs2,
__ASSERT(timing->prop_seg + timing->phase_seg1 >= timing->phase_seg2,
"PROP + BS1 >= BS2");
__ASSERT(dev_cfg->tq_bs2 > dev_cfg->tq_sjw, "BS2 > SJW");
if (dev_cfg->osc_freq % (bit_length * bitrate * 2)) {
LOG_ERR("Prescaler is not a natural number! "
"prescaler = osc_rate / ((PROP + SEG1 + SEG2 + 1) "
"* bitrate * 2)\n"
"prescaler = %d / ((%d + %d + %d + 1) * %d * 2)",
dev_cfg->osc_freq, dev_cfg->tq_prop,
dev_cfg->tq_bs1, dev_cfg->tq_bs2, bitrate);
}
__ASSERT(timing->phase_seg2 > timing->sjw, "BS2 > SJW");
config_buf[0] = cnf3;
config_buf[1] = cnf2;
@ -366,10 +364,7 @@ static int mcp2515_configure(const struct device *dev, enum can_mode mode,
k_mutex_lock(&dev_data->mutex, K_FOREVER);
/* Wait 128 OSC1 clock cycles at 1MHz (minimum clock in frequency)
* see MCP2515 datasheet section 8.1 Oscillator Start-up Timer
*/
k_usleep(128);
k_usleep(MCP2515_OSC_STARTUP_US);
/* will enter configuration mode automatically */
ret = mcp2515_cmd_soft_reset(dev);
@ -378,7 +373,7 @@ static int mcp2515_configure(const struct device *dev, enum can_mode mode,
goto done;
}
k_usleep(128);
k_usleep(MCP2515_OSC_STARTUP_US);
ret = mcp2515_get_mode(dev, &reset_mode);
if (ret < 0) {
@ -413,7 +408,19 @@ static int mcp2515_configure(const struct device *dev, enum can_mode mode,
}
done:
ret = mcp2515_set_mode(dev,
k_mutex_unlock(&dev_data->mutex);
return ret;
}
static int mcp2515_set_mode(const struct device *dev, enum can_mode mode)
{
struct mcp2515_data *dev_data = DEV_DATA(dev);
int ret;
k_mutex_lock(&dev_data->mutex, K_FOREVER);
k_usleep(MCP2515_OSC_STARTUP_US);
ret = mcp2515_set_mode_int(dev,
mcp2515_convert_canmode_to_mcp2515mode(mode));
if (ret < 0) {
LOG_ERR("Failed to set the mode [%d]", ret);
@ -772,7 +779,8 @@ static void mcp2515_int_gpio_callback(const struct device *dev,
}
static const struct can_driver_api can_api_funcs = {
.configure = mcp2515_configure,
.set_timing = mcp2515_set_timing,
.set_mode = mcp2515_set_mode,
.send = mcp2515_send,
.attach_isr = mcp2515_attach_isr,
.detach = mcp2515_detach,
@ -780,7 +788,22 @@ static const struct can_driver_api can_api_funcs = {
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
.recover = mcp2515_recover,
#endif
.register_state_change_isr = mcp2515_register_state_change_isr
.register_state_change_isr = mcp2515_register_state_change_isr,
.get_core_clock = mcp2515_get_core_clock,
.timing_min = {
.sjw = 0x1,
.prop_seg = 0x01,
.phase_seg1 = 0x01,
.phase_seg2 = 0x01,
.prescaler = 0x01
},
.timing_max = {
.sjw = 0x04,
.prop_seg = 0x08,
.phase_seg1 = 0x08,
.phase_seg2 = 0x08,
.prescaler = 0x20
}
};
@ -789,6 +812,7 @@ static int mcp2515_init(const struct device *dev)
const struct mcp2515_config *dev_cfg = DEV_CFG(dev);
struct mcp2515_data *dev_data = DEV_DATA(dev);
int ret;
struct can_timing timing;
k_sem_init(&dev_data->int_sem, 0, 1);
k_mutex_init(&dev_data->mutex);
@ -867,7 +891,33 @@ static int mcp2515_init(const struct device *dev)
(void)memset(dev_data->filter, 0, sizeof(dev_data->filter));
dev_data->old_state = CAN_ERROR_ACTIVE;
ret = mcp2515_configure(dev, CAN_NORMAL_MODE, dev_cfg->bus_speed);
timing.sjw = dev_cfg->tq_sjw;
if (dev_cfg->sample_point) {
ret = can_calc_timing(dev, &timing, dev_cfg->bus_speed,
dev_cfg->sample_point);
if (ret == -EINVAL) {
LOG_ERR("Can't find timing for given param");
return -EIO;
}
LOG_DBG("Presc: %d, BS1: %d, BS2: %d",
timing.prescaler, timing.phase_seg1, timing.phase_seg2);
LOG_DBG("Sample-point err : %d", ret);
} else {
timing.prop_seg = dev_cfg->tq_prop;
timing.phase_seg1 = dev_cfg->tq_bs1;
timing.phase_seg2 = dev_cfg->tq_bs2;
ret = can_calc_prescaler(dev, &timing, dev_cfg->bus_speed);
if (ret) {
LOG_WRN("Bitrate error: %d", ret);
}
}
ret = can_set_mode(dev, CAN_NORMAL_MODE);
if (ret) {
return ret;
}
ret = can_set_timing(dev, &timing, NULL);
return ret;
}
@ -900,11 +950,18 @@ static const struct mcp2515_config mcp2515_config_1 = {
.spi_cs_flags = DT_INST_SPI_DEV_CS_GPIOS_FLAGS(0),
#endif /* DT_INST_SPI_DEV_HAS_CS_GPIOS(0) */
.tq_sjw = DT_INST_PROP(0, sjw),
#if DT_INST_PROP(0, prop_seg) > 0 && \
DT_INST_PROP(0, phase_seg1) > 0 && \
DT_INST_PROP(0, phase_seg2) > 0
.tq_prop = DT_INST_PROP(0, prop_seg),
.tq_bs1 = DT_INST_PROP(0, phase_seg1),
.tq_bs2 = DT_INST_PROP(0, phase_seg2),
#endif
.bus_speed = DT_INST_PROP(0, bus_speed),
.osc_freq = DT_INST_PROP(0, osc_freq)
#if DT_INST_PROP(0, sample_point)
.sample_point = DT_INST_PROP(0, sample_point),
#endif
};
DEVICE_AND_API_INIT(can_mcp2515_1, DT_INST_LABEL(0), &mcp2515_init,

View file

@ -78,8 +78,15 @@ struct mcp2515_config {
uint8_t tq_bs2;
uint32_t bus_speed;
uint32_t osc_freq;
uint16_t sample_point;
};
/*
* Startup time of 128 OSC1 clock cycles at 1MHz (minimum clock in frequency)
* see MCP2515 datasheet section 8.1 Oscillator Start-up Timer
*/
#define MCP2515_OSC_STARTUP_US 128U
/* MCP2515 Opcodes */
#define MCP2515_OPCODE_WRITE 0x02
#define MCP2515_OPCODE_READ 0x03

View file

@ -56,6 +56,7 @@ struct mcux_flexcan_config {
clock_control_subsys_t clock_subsys;
int clk_source;
uint32_t bitrate;
uint32_t sample_point;
uint32_t sjw;
uint32_t prop_seg;
uint32_t phase_seg1;
@ -91,36 +92,69 @@ struct mcux_flexcan_data {
struct mcux_flexcan_tx_callback tx_cbs[MCUX_FLEXCAN_MAX_TX];
enum can_state state;
can_state_change_isr_t state_change_isr;
flexcan_timing_config_t timing;
};
static int mcux_flexcan_configure(const struct device *dev,
enum can_mode mode,
uint32_t bitrate)
static int mcux_flexcan_get_core_clock(const struct device *dev, uint32_t *rate)
{
const struct mcux_flexcan_config *config = dev->config;
flexcan_config_t flexcan_config;
const struct device *clock_dev;
uint32_t clock_freq;
clock_dev = device_get_binding(config->clock_name);
if (clock_dev == NULL) {
return -EIO;
}
return clock_control_get_rate(clock_dev, config->clock_subsys, rate);
}
static int mcux_flexcan_set_timing(const struct device *dev,
const struct can_timing *timing,
const struct can_timing *timing_data)
{
ARG_UNUSED(timing_data);
struct mcux_flexcan_data *data = dev->data;
const struct mcux_flexcan_config *config = dev->config;
if (!timing) {
return -EINVAL;
}
if (clock_control_get_rate(clock_dev, config->clock_subsys,
&clock_freq)) {
return -EINVAL;
data->timing.preDivider = timing->prescaler;
data->timing.rJumpwidth = timing->sjw;
data->timing.phaseSeg1 = timing->phase_seg1;
data->timing.phaseSeg2 = timing->phase_seg2;
data->timing.propSeg = timing->prop_seg;
FLEXCAN_SetTimingConfig(config->base, &data->timing);
return 0;
}
static int mcux_flexcan_set_mode(const struct device *dev, enum can_mode mode)
{
struct mcux_flexcan_data *data = dev->data;
const struct mcux_flexcan_config *config = dev->config;
flexcan_config_t flexcan_config;
uint32_t clock_freq;
int ret;
ret = mcux_flexcan_get_core_clock(dev, &clock_freq);
if (ret != 0) {
return -EIO;
}
FLEXCAN_GetDefaultConfig(&flexcan_config);
flexcan_config.clkSrc = config->clk_source;
flexcan_config.baudRate = bitrate ? bitrate : config->bitrate;
flexcan_config.baudRate = clock_freq /
(1U + data->timing.propSeg + data->timing.phaseSeg1 +
data->timing.phaseSeg2) / data->timing.preDivider;
flexcan_config.enableIndividMask = true;
flexcan_config.timingConfig.rJumpwidth = config->sjw;
flexcan_config.timingConfig.propSeg = config->prop_seg;
flexcan_config.timingConfig.phaseSeg1 = config->phase_seg1;
flexcan_config.timingConfig.phaseSeg2 = config->phase_seg2;
flexcan_config.timingConfig.rJumpwidth = data->timing.rJumpwidth;
flexcan_config.timingConfig.propSeg = data->timing.propSeg;
flexcan_config.timingConfig.phaseSeg1 = data->timing.phaseSeg1;
flexcan_config.timingConfig.phaseSeg2 = data->timing.phaseSeg2;
if (mode == CAN_LOOPBACK_MODE || mode == CAN_SILENT_LOOPBACK_MODE) {
flexcan_config.enableLoopBack = true;
@ -623,6 +657,7 @@ static int mcux_flexcan_init(const struct device *dev)
{
const struct mcux_flexcan_config *config = dev->config;
struct mcux_flexcan_data *data = dev->data;
struct can_timing timing;
int err;
int i;
@ -633,7 +668,37 @@ static int mcux_flexcan_init(const struct device *dev)
k_sem_init(&data->tx_cbs[i].done, 0, 1);
}
err = mcux_flexcan_configure(dev, CAN_NORMAL_MODE, 0);
timing.sjw = config->sjw;
if (config->sample_point) {
err = can_calc_timing(dev, &timing, config->bitrate,
config->sample_point);
if (err == -EINVAL) {
LOG_ERR("Can't find timing for given param");
return -EIO;
}
LOG_DBG("Presc: %d, Seg1S1: %d, Seg2: %d",
timing.prescaler, timing.phase_seg1, timing.phase_seg2);
LOG_DBG("Sample-point err : %d", err);
} else if (config->phase_seg1) {
timing.prop_seg = config->prop_seg;
timing.phase_seg1 = config->phase_seg1;
timing.phase_seg2 = config->phase_seg2;
err = can_calc_prescaler(dev, &timing, config->bitrate);
if (err) {
LOG_WRN("Bitrate error: %d", err);
}
} else {
LOG_ERR("Timing not configured");
return -EINVAL;
}
data->timing.preDivider = timing.prescaler;
data->timing.rJumpwidth = timing.sjw;
data->timing.phaseSeg1 = timing.phase_seg1;
data->timing.phaseSeg2 = timing.phase_seg2;
data->timing.propSeg = timing.prop_seg;
err = mcux_flexcan_set_mode(dev, CAN_NORMAL_MODE);
if (err) {
return err;
}
@ -654,7 +719,8 @@ static int mcux_flexcan_init(const struct device *dev)
}
static const struct can_driver_api mcux_flexcan_driver_api = {
.configure = mcux_flexcan_configure,
.set_mode = mcux_flexcan_set_mode,
.set_timing = mcux_flexcan_set_timing,
.send = mcux_flexcan_send,
.attach_isr = mcux_flexcan_attach_isr,
.detach = mcux_flexcan_detach,
@ -662,7 +728,22 @@ static const struct can_driver_api mcux_flexcan_driver_api = {
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
.recover = mcux_flexcan_recover,
#endif
.register_state_change_isr = mcux_flexcan_register_state_change_isr
.register_state_change_isr = mcux_flexcan_register_state_change_isr,
.get_core_clock = mcux_flexcan_get_core_clock,
.timing_min = {
.sjw = 0x1,
.prop_seg = 0x01,
.phase_seg1 = 0x01,
.phase_seg2 = 0x01,
.prescaler = 0x01
},
.timing_max = {
.sjw = 0x03,
.prop_seg = 0x07,
.phase_seg1 = 0x07,
.phase_seg2 = 0x07,
.prescaler = 0xFF
}
};
#define FLEXCAN_IRQ_CODE(id, name) \

View file

@ -240,14 +240,21 @@ static int cmd_config(const struct shell *shell, size_t argc, char **argv)
mode = CAN_NORMAL_MODE;
}
ret = can_set_mode(can_dev, mode);
if (ret) {
shell_error(shell, "Failed to set mode [%d]",
ret);
return ret;
}
pos = read_bitrate(shell, pos, argv, &bitrate);
if (pos < 0) {
return -EINVAL;
}
ret = can_configure(can_dev, mode, bitrate);
ret = can_set_bitrate(can_dev, bitrate, 0);
if (ret) {
shell_error(shell, "Failed to configure CAN controller [%d]",
shell_error(shell, "Failed to set bitrate [%d]",
ret);
return ret;
}

View file

@ -290,69 +290,14 @@ static int can_leave_sleep_mode(CAN_TypeDef *can)
return 0;
}
int can_stm32_runtime_configure(const struct device *dev, enum can_mode mode,
uint32_t bitrate)
int can_stm32_set_mode(const struct device *dev, enum can_mode mode)
{
CAN_HandleTypeDef hcan;
const struct can_stm32_config *cfg = DEV_CFG(dev);
CAN_TypeDef *can = cfg->can;
struct can_stm32_data *data = DEV_DATA(dev);
const struct device *clock;
uint32_t clock_rate;
uint32_t prescaler;
uint32_t reg_mode;
uint32_t ts1;
uint32_t ts2;
uint32_t sjw;
int ret;
clock = device_get_binding(STM32_CLOCK_CONTROL_NAME);
__ASSERT_NO_MSG(clock);
hcan.Instance = can;
ret = clock_control_get_rate(clock, (clock_control_subsys_t *) &cfg->pclken,
&clock_rate);
if (ret != 0) {
LOG_ERR("Failed call clock_control_get_rate: return [%d]", ret);
return -EIO;
}
if (!bitrate) {
bitrate = cfg->bus_speed;
}
prescaler = clock_rate / (BIT_SEG_LENGTH(cfg) * bitrate);
if (prescaler == 0U || prescaler > 1024) {
LOG_ERR("HAL_CAN_Init failed: prescaler > max (%d > 1024)",
prescaler);
return -EINVAL;
}
if (clock_rate % (BIT_SEG_LENGTH(cfg) * bitrate)) {
LOG_ERR("Prescaler is not a natural number! "
"prescaler = clock_rate / ((PROP_SEG1 + SEG2 + 1)"
" * bus_speed); "
"prescaler = %d / ((%d + %d + 1) * %d)",
clock_rate,
cfg->prop_ts1,
cfg->ts2,
bitrate);
}
__ASSERT(cfg->sjw >= 1, "SJW minimum is 1");
__ASSERT(cfg->sjw <= 4, "SJW maximum is 4");
__ASSERT(cfg->prop_ts1 >= 1, "PROP_TS1 minimum is 1");
__ASSERT(cfg->prop_ts1 <= 16, "PROP_TS1 maximum is 16");
__ASSERT(cfg->ts2 >= 1, "TS2 minimum is 1");
__ASSERT(cfg->ts2 <= 8, "TS2 maximum is 8");
ts1 = ((cfg->prop_ts1 - 1) & 0x0F) << CAN_BTR_TS1_Pos;
ts2 = ((cfg->ts2 - 1) & 0x07) << CAN_BTR_TS2_Pos;
sjw = ((cfg->sjw - 1) & 0x07) << CAN_BTR_SJW_Pos;
reg_mode = (mode == CAN_NORMAL_MODE) ? 0U :
(mode == CAN_LOOPBACK_MODE) ? CAN_BTR_LBKM :
(mode == CAN_SILENT_MODE) ? CAN_BTR_SILM :
CAN_BTR_LBKM | CAN_BTR_SILM;
LOG_DBG("Set mode %d", mode);
k_mutex_lock(&data->inst_mutex, K_FOREVER);
ret = can_enter_init_mode(can);
@ -361,26 +306,97 @@ int can_stm32_runtime_configure(const struct device *dev, enum can_mode mode,
goto done;
}
can->BTR = reg_mode | sjw | ts1 | ts2 | (prescaler - 1U);
switch (mode) {
case CAN_NORMAL_MODE:
can->BTR &= ~(CAN_BTR_LBKM | CAN_BTR_SILM);
break;
case CAN_LOOPBACK_MODE:
can->BTR &= ~(CAN_BTR_SILM);
can->BTR |= CAN_BTR_LBKM;
break;
case CAN_SILENT_MODE:
can->BTR &= ~(CAN_BTR_LBKM);
can->BTR |= CAN_BTR_SILM;
break;
case CAN_SILENT_LOOPBACK_MODE:
can->BTR |= CAN_BTR_LBKM | CAN_BTR_SILM;
break;
default:
break;
}
done:
ret = can_leave_init_mode(can);
if (ret) {
LOG_ERR("Failed to leave init mode");
}
k_mutex_unlock(&data->inst_mutex);
return ret;
}
int can_stm32_set_timing(const struct device *dev,
const struct can_timing *timing,
const struct can_timing *timing_data)
{
const struct can_stm32_config *cfg = DEV_CFG(dev);
CAN_TypeDef *can = cfg->can;
struct can_stm32_data *data = DEV_DATA(dev);
int ret = -EIO;
ARG_UNUSED(timing_data);
k_mutex_lock(&data->inst_mutex, K_FOREVER);
ret = can_enter_init_mode(can);
if (ret) {
LOG_ERR("Failed to enter init mode");
goto done;
}
can->BTR &= ~(CAN_BTR_BRP_Msk | CAN_BTR_TS1_Msk |
CAN_BTR_TS2_Msk | CAN_BTR_SJW_Msk);
can->BTR |= (((timing->phase_seg1 - 1) & 0x0F) << CAN_BTR_TS1_Pos) |
(((timing->phase_seg2 - 1) & 0x07) << CAN_BTR_TS2_Pos) |
(((timing->sjw - 1) & 0x07) << CAN_BTR_SJW_Pos);
ret = can_leave_init_mode(can);
if (ret) {
LOG_ERR("Failed to leave init mode");
goto done;
} else {
ret = 0;
}
LOG_DBG("Runtime configure of %s done", dev->name);
ret = 0;
done:
k_mutex_unlock(&data->inst_mutex);
return ret;
}
int can_stm32_get_core_clock(const struct device *dev, uint32_t *rate)
{
const struct can_stm32_config *cfg = DEV_CFG(dev);
const struct device *clock;
int ret;
clock = device_get_binding(STM32_CLOCK_CONTROL_NAME);
__ASSERT_NO_MSG(clock);
ret = clock_control_get_rate(clock,
(clock_control_subsys_t *) &cfg->pclken,
rate);
if (ret != 0) {
LOG_ERR("Failed call clock_control_get_rate: return [%d]", ret);
return -EIO;
}
return 0;
}
static int can_stm32_init(const struct device *dev)
{
const struct can_stm32_config *cfg = DEV_CFG(dev);
struct can_stm32_data *data = DEV_DATA(dev);
CAN_TypeDef *can = cfg->can;
struct can_timing timing;
#if DT_NODE_HAS_STATUS(DT_NODELABEL(can2), okay)
CAN_TypeDef *master_can = cfg->master_can;
#endif
@ -445,8 +461,36 @@ static int can_stm32_init(const struct device *dev)
#ifdef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
can->MCR |= CAN_MCR_ABOM;
#endif
timing.sjw = cfg->sjw;
if (cfg->sample_point) {
ret = can_calc_timing(dev, &timing, cfg->bus_speed,
cfg->sample_point);
if (ret == -EINVAL) {
LOG_ERR("Can't find timing for given param");
return -EIO;
}
LOG_DBG("Presc: %d, TS1: %d, TS2: %d",
timing.prescaler, timing.phase_seg1, timing.phase_seg2);
LOG_DBG("Sample-point err : %d", ret);
} else if (cfg->prop_ts1) {
timing.prop_seg = 0;
timing.phase_seg1 = cfg->prop_ts1;
timing.phase_seg2 = cfg->ts2;
ret = can_calc_prescaler(dev, &timing, cfg->bus_speed);
if (ret) {
LOG_WRN("Bitrate error: %d", ret);
}
} else {
LOG_ERR("Timing not configured");
return -EINVAL;
}
ret = can_stm32_runtime_configure(dev, CAN_NORMAL_MODE, 0);
ret = can_stm32_set_timing(dev, &timing, NULL);
if (ret) {
return ret;
}
ret = can_stm32_set_mode(dev, CAN_NORMAL_MODE);
if (ret) {
return ret;
}
@ -1037,7 +1081,8 @@ void can_stm32_detach(const struct device *dev, int filter_nr)
}
static const struct can_driver_api can_api_funcs = {
.configure = can_stm32_runtime_configure,
.set_mode = can_stm32_set_mode,
.set_timing = can_stm32_set_timing,
.send = can_stm32_send,
.attach_isr = can_stm32_attach_isr,
.detach = can_stm32_detach,
@ -1045,7 +1090,22 @@ static const struct can_driver_api can_api_funcs = {
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
.recover = can_stm32_recover,
#endif
.register_state_change_isr = can_stm32_register_state_change_isr
.register_state_change_isr = can_stm32_register_state_change_isr,
.get_core_clock = can_stm32_get_core_clock,
.timing_min = {
.sjw = 0x1,
.prop_seg = 0x00,
.phase_seg1 = 0x01,
.phase_seg2 = 0x01,
.prescaler = 0x01
},
.timing_max = {
.sjw = 0x07,
.prop_seg = 0x00,
.phase_seg1 = 0x0F,
.phase_seg2 = 0x07,
.prescaler = 0x400
}
};
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(can1), st_stm32_can, okay)
@ -1059,10 +1119,16 @@ static const struct can_stm32_config can_stm32_cfg_1 = {
.can = (CAN_TypeDef *)DT_REG_ADDR(DT_NODELABEL(can1)),
.master_can = (CAN_TypeDef *)DT_REG_ADDR(DT_NODELABEL(can1)),
.bus_speed = DT_PROP(DT_NODELABEL(can1), bus_speed),
#if DT_PROP(DT_NODELABEL(can1), sample_point) > 0
.sample_point = DT_PROP(DT_NODELABEL(can1), sample_point),
#endif
.sjw = DT_PROP(DT_NODELABEL(can1), sjw),
#if DT_PROP(DT_NODELABEL(can1), phase_seg1) > 0 && \
DT_PROP(DT_NODELABEL(can1), phase_seg2) > 0
.prop_ts1 = DT_PROP(DT_NODELABEL(can1), prop_seg) +
DT_PROP(DT_NODELABEL(can1), phase_seg1),
.ts2 = DT_PROP(DT_NODELABEL(can1), phase_seg2),
#endif
.pclken = {
.enr = DT_CLOCKS_CELL(DT_NODELABEL(can1), bits),
.bus = DT_CLOCKS_CELL(DT_NODELABEL(can1), bus),
@ -1154,10 +1220,16 @@ static const struct can_stm32_config can_stm32_cfg_2 = {
.master_can = (CAN_TypeDef *)DT_PROP(DT_NODELABEL(can2),
master_can_reg),
.bus_speed = DT_PROP(DT_NODELABEL(can2), bus_speed),
#if DT_PROP(DT_NODELABEL(can2), sample_point) > 0
.sample_point = DT_PROP(DT_NODELABEL(can2), sample_point),
#endif
.sjw = DT_PROP(DT_NODELABEL(can2), sjw),
#if DT_PROP(DT_NODELABEL(can2), phase_seg1) > 0 && \
DT_PROP(DT_NODELABEL(can2), phase_seg2) > 0
.prop_ts1 = DT_PROP(DT_NODELABEL(can2), prop_seg) +
DT_PROP(DT_NODELABEL(can2), phase_seg1),
.ts2 = DT_PROP(DT_NODELABEL(can2), phase_seg2),
#endif
.pclken = {
.enr = DT_CLOCKS_CELL(DT_NODELABEL(can2), bits),
.bus = DT_CLOCKS_CELL(DT_NODELABEL(can2), bus),

View file

@ -71,6 +71,7 @@ struct can_stm32_config {
CAN_TypeDef *can; /*!< CAN Registers*/
CAN_TypeDef *master_can; /*!< CAN Registers for shared filter */
uint32_t bus_speed;
uint16_t sample_point;
uint8_t sjw;
uint8_t prop_ts1;
uint8_t ts2;

View file

@ -23,13 +23,20 @@ properties:
description: Resynchronization jump width (ISO 11898-1)
prop-seg:
type: int
required: true
required: false
description: Time quantums of propagation segment (ISO 11898-1)
phase-seg1:
type: int
required: true
required: false
description: Time quantums of phase buffer 1 segment (ISO 11898-1)
phase-seg2:
type: int
required: true
required: false
description: Time quantums of phase buffer 2 segment (ISO 11898-1)
sample-point:
type: int
required: false
description: >
Sample point in permille.
This param is required if segments are not given.
If the sample point is given, the segments are ignored.

View file

@ -0,0 +1,32 @@
# Common fields for CAN-FD controllers
include: can-controller.yaml
properties:
bus-speed-data:
type: int
required: true
description: data phase bus speed in Baud/s
sjw-data:
type: int
required: true
description: Resynchronization jump width for the data phase. (ISO11898-1:2015)
prop-seg-data:
type: int
required: false
description: Time quantums of propagation segment for the data phase. (ISO11898-1:2015)
phase-seg1-data:
type: int
required: false
description: Time quantums of phase buffer 1 segment for the data phase. (ISO11898-1:2015)
phase-seg2-data:
type: int
required: false
description: Time quantums of phase buffer 2 segment for the data phase. (ISO11898-1:2015)
sample-point-data:
type: int
required: false
description: >
Sample point in permille for the data phase.
This param is required if segments are not given.
If the sample point is given, the segments are ignored.

View file

@ -98,7 +98,7 @@ enum can_mode {
/*Controller is in loopback mode (receive own messages)*/
CAN_LOOPBACK_MODE,
/*Combination of loopback and silent*/
CAN_SILENT_LOOPBACK_MODE
CAN_SILENT_LOOPBACK_MODE,
};
/**
@ -236,6 +236,43 @@ struct can_bus_err_cnt {
uint8_t rx_err_cnt;
};
/**
* @brief canbus timings
*
* Used to pass bus timing values to the config and bitrate calculator function.
*
* The propagation segment represents the time of the signal propagation.
* Phase segment 1 and phase segment 2 define the sampling point.
* prop_seg and phase_seg1 affect the sampling-point in the same way and some
* controllers only have a register for the sum of those two. The sync segment
* always has a length of 1 tq
* +---------+----------+------------+------------+
* |sync_seg | prop_seg | phase_seg1 | phase_seg2 |
* +---------+----------+------------+------------+
* ^
* Sampling-Point
* 1 tq (time quantum) has the length of 1/(core_clock / prescaler)
* The bitrate is defined by the core clock divided by the prescaler and the
* sum of the segments.
* br = (core_clock / prescaler) / (1 + prop_seg + phase_seg1 + phase_seg2)
* The resynchronization jump width (SJW) defines the amount of time quantum
* the sample point can be moved.
* The sample point is moved when resynchronization is needed.
*/
struct can_timing {
/** Synchronisation jump width*/
uint16_t sjw;
/** Propagation Segment */
uint16_t prop_seg;
/** Phase Segment 1 */
uint16_t phase_seg1;
/** Phase Segment 2 */
uint16_t phase_seg2;
/** Prescaler value */
uint16_t prescaler;
};
/**
* @typedef can_tx_callback_t
* @brief Define the application callback handler function signature
@ -265,8 +302,11 @@ typedef void (*can_rx_callback_t)(struct zcan_frame *msg, void *arg);
typedef void(*can_state_change_isr_t)(enum can_state state,
struct can_bus_err_cnt err_cnt);
typedef int (*can_configure_t)(const struct device *dev, enum can_mode mode,
uint32_t bitrate);
typedef int (*can_set_timing_t)(const struct device *dev,
const struct can_timing *timing,
const struct can_timing *timing_data);
typedef int (*can_set_mode_t)(const struct device *dev, enum can_mode mode);
typedef int (*can_send_t)(const struct device *dev,
const struct zcan_frame *msg,
@ -293,6 +333,8 @@ typedef enum can_state (*can_get_state_t)(const struct device *dev,
typedef void(*can_register_state_change_isr_t)(const struct device *dev,
can_state_change_isr_t isr);
typedef int (*can_get_core_clock_t)(const struct device *dev, uint32_t *rate);
#ifndef CONFIG_CAN_WORKQ_FRAMES_BUF_CNT
#define CONFIG_CAN_WORKQ_FRAMES_BUF_CNT 4
#endif
@ -316,7 +358,8 @@ struct zcan_work {
};
__subsystem struct can_driver_api {
can_configure_t configure;
can_set_mode_t set_mode;
can_set_timing_t set_timing;
can_send_t send;
can_attach_isr_t attach_isr;
can_detach_t detach;
@ -325,7 +368,17 @@ __subsystem struct can_driver_api {
#endif
can_get_state_t get_state;
can_register_state_change_isr_t register_state_change_isr;
can_get_core_clock_t get_core_clock;
/* Min values for the timing registers */
struct can_timing timing_min;
/* Max values for the timing registers */
struct can_timing timing_max;
#ifdef CONFIG_CAN_FD_MODE
/* Min values for the timing registers during the data phase */
struct can_timing timing_min_data;
/* Max values for the timing registers during the data phase */
struct can_timing timing_max_data;
#endif
};
/**
@ -508,6 +561,175 @@ static inline void z_impl_can_detach(const struct device *dev, int filter_id)
return api->detach(dev, filter_id);
}
/**
* @brief Read the core clock value
*
* Returns the core clock value. One time quantum is 1/core clock.
*
* @param dev Pointer to the device structure for the driver instance.
* @param[out] rate controller clock rate
*
* @retval 0 on success
* @retval negative on error
*/
__syscall int can_get_core_clock(const struct device *dev, uint32_t *rate);
static inline int z_impl_can_get_core_clock(const struct device *dev,
uint32_t *rate)
{
const struct can_driver_api *api =
(const struct can_driver_api *)dev->api;
return api->get_core_clock(dev, rate);
}
/**
* @brief Calculate timing parameters from bitrate and sample point
*
* Calculate the timing parameters from a given bitrate in bits/s and the
* sampling point in permill (1/1000) of the entire bit time.
* The bitrate must alway match perfectly. If no result can be given for the,
* give parameters, -EINVAL is returned.
* The sample_pnt does not always match perfectly. The algorithm tries to find
* the best match possible.
*
* @param dev Pointer to the device structure for the driver instance.
* @param res Result is written into the can_timing struct provided.
* @param bitrate Target bitrate in bits/s
* @param sample_pnt Sampling point in permill of the entire bit time.
*
* @retval Positive sample point error on success
* @retval -EINVAL if there is no solution for the desired values
* @retval -EIO if core_clock is not available
*/
int can_calc_timing(const struct device *dev, struct can_timing *res,
uint32_t bitrate, uint16_t sample_pnt);
#ifdef CONFIG_CAN_FD_MODE
/**
* @brief Calculate timing parameters for the data phase
*
* Same as can_calc_timing but with the max and min values from the data phase.
*
* @param dev Pointer to the device structure for the driver instance.
* @param res Result is written into the can_timing struct provided.
* @param bitrate Target bitrate for the data phase in bits/s
* @param sample_pnt Sampling point data phase in permille of the entire bit time.
*
* @retval Positive sample point error on success
* @retval -EINVAL if there is no solution for the desired values
* @retval -EIO if core_clock is not available
*/
int can_calc_timing_data(const struct device *dev, struct can_timing *res,
uint32_t bitrate, uint16_t sample_pnt);
#endif
/**
* @brief Fill in the prescaler value for a given bitrate and timing
*
* Fill the prescaler value in the timing struct.
* sjw, prop_seg, phase_seg1 and phase_seg2 must be given.
* The returned bitrate error is reminder of the devision of the clockrate by
* the bitrate times the timing segments.
*
* @param dev Pointer to the device structure for the driver instance.
* @param timing Result is written into the can_timing struct provided.
* @param bitrate Target bitrate.
*
* @retval bitrate error
* @retval negative on error
*/
int can_calc_prescaler(const struct device *dev, struct can_timing *timing,
uint32_t bitrate);
/**
* @brief Set the controller to the given mode
*
* @param dev Pointer to the device structure for the driver instance.
* @param mode Operation mode
*
* @retval 0 If successful.
* @retval -EIO General input / output error, failed to configure device.
*/
__syscall int can_set_mode(const struct device *dev, enum can_mode mode);
static inline int z_impl_can_set_mode(const struct device *dev,
enum can_mode mode)
{
const struct can_driver_api *api =
(const struct can_driver_api *)dev->api;
return api->set_mode(dev, mode);
}
/**
* @brief Configure timing of a host controller.
*
* The second parameter timing_data is only relevant for CAN-FD.
* If the controller does not support CAN-FD or the FD mode is not enabled,
* this parameter is ignored.
*
* @param dev Pointer to the device structure for the driver instance.
* @param timing Bus timings
* @param timing_data Bus timings for data phase (CAN-FD only)
*
* @retval 0 If successful.
* @retval -EIO General input / output error, failed to configure device.
*/
__syscall int can_set_timing(const struct device *dev,
const struct can_timing *timing,
const struct can_timing *timing_data);
static inline int z_impl_can_set_timing(const struct device *dev,
const struct can_timing *timing,
const struct can_timing *timing_data)
{
const struct can_driver_api *api =
(const struct can_driver_api *)dev->api;
return api->set_timing(dev, timing, timing_data);
}
/**
* @brief Set the bitrate of the CAN-FD controller
*
* The sample point is set to the CiA DS 301 reccommended value of 87.5%
*
* @param dev Pointer to the device structure for the driver instance.
* @param bitrate Desired arbitration phase bitrate
* @param bitrate_data Desired data phase bitrate
*
* @retval 0 If successful.
* @retval -EINVAL bitrate cannot be reached.
* @retval -EIO General input / output error, failed to set bitrate.
*/
static inline int can_set_bitrate(const struct device *dev,
uint32_t bitrate,
uint32_t bitrate_data)
{
struct can_timing timing;
#ifdef CONFIG_CAN_FD_MODE
struct can_timing timing_data;
#endif
int ret;
ret = can_calc_timing(dev, &timing, bitrate, 875);
if (ret < 0) {
return -EINVAL;
}
#ifdef CONFIG_CAN_FD_MODE
ret = can_calc_timing_data(dev, &timing_data, bitrate_data, 875);
if (ret < 0) {
return -EINVAL;
}
return can_set_timing(dev, &timing, &timing_data);
#else
return can_set_timing(dev, &timing, NULL);
#endif /* CONFIG_CAN_FD_MODE */
}
/**
* @brief Configure operation of a host controller.
*
@ -518,19 +740,18 @@ static inline void z_impl_can_detach(const struct device *dev, int filter_id)
* @retval 0 If successful.
* @retval -EIO General input / output error, failed to configure device.
*/
__syscall int can_configure(const struct device *dev, enum can_mode mode,
uint32_t bitrate);
static inline int z_impl_can_configure(const struct device *dev,
enum can_mode mode,
static inline int can_configure(const struct device *dev, enum can_mode mode,
uint32_t bitrate)
{
const struct can_driver_api *api =
(const struct can_driver_api *)dev->api;
int err = can_set_bitrate(dev, bitrate, 0);
if (err != 0) {
return err;
}
return api->configure(dev, mode, bitrate);
return can_set_mode(dev, mode);
}
/**
* @brief Get current state
*

View file

@ -206,7 +206,7 @@ void main(void)
}
#ifdef CONFIG_LOOPBACK_MODE
can_configure(can_dev, CAN_LOOPBACK_MODE, 125000);
can_set_mode(can_dev, CAN_LOOPBACK_MODE);
#endif
#if DT_PHA_HAS_CELL(DT_ALIAS(led0), gpios, pin) && \

View file

@ -212,7 +212,13 @@ CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule,
txArray[i].bufferFull = false;
}
err = can_configure(CANmodule->dev, CAN_NORMAL_MODE, KHZ(CANbitRate));
err = can_set_bitrate(CANmodule->dev, KHZ(CANbitRate), 0);
if (err) {
LOG_ERR("failed to configure CAN bitrate (err %d)", err);
return CO_ERROR_ILLEGAL_ARGUMENT;
}
err = can_set_mode(CANmodule->dev, CAN_NORMAL_MODE);
if (err) {
LOG_ERR("failed to configure CAN interface (err %d)", err);
return CO_ERROR_ILLEGAL_ARGUMENT;

View file

@ -414,7 +414,7 @@ static void test_set_loopback(void)
{
int ret;
ret = can_configure(can_dev, CAN_LOOPBACK_MODE, 0);
ret = can_set_mode(can_dev, CAN_LOOPBACK_MODE);
zassert_equal(ret, 0, "Can't set loopback-mode. Err: %d", ret);
}

View file

@ -133,7 +133,7 @@ static void test_filter_handling(void)
can_dev = device_get_binding(DT_CHOSEN_ZEPHYR_CAN_PRIMARY_LABEL);
ret = can_configure(can_dev, CAN_LOOPBACK_MODE, 0);
ret = can_set_mode(can_dev, CAN_LOOPBACK_MODE);
filter_id_1 = can_attach_msgq(can_dev, &can_msgq, &test_ext_masked_filter);
zassert_not_equal(filter_id_1, CAN_NO_FREE_FILTER,

View file

@ -882,7 +882,7 @@ void test_main(void)
can_dev = device_get_binding(CAN_DEVICE_NAME);
zassert_not_null(can_dev, "CAN device not not found");
ret = can_configure(can_dev, CAN_LOOPBACK_MODE, 0);
ret = can_set_mode(can_dev, CAN_LOOPBACK_MODE);
zassert_equal(ret, 0, "Failed to set loopback mode [%d]", ret);
k_sem_init(&send_compl_sem, 0, 1);

View file

@ -423,7 +423,7 @@ void test_main(void)
can_dev = device_get_binding(CAN_DEVICE_NAME);
zassert_not_null(can_dev, "CAN device not not found");
ret = can_configure(can_dev, CAN_LOOPBACK_MODE, 0);
ret = can_set_mode(can_dev, CAN_LOOPBACK_MODE);
zassert_equal(ret, 0, "Configuring loopback mode failed (%d)", ret);
ztest_test_suite(isotp,