/* can-calc-bit-timing.c: Calculate CAN bit timing parameters
*
* Copyright (C) 2008 Wolfgang Grandegger <wg@grandegger.com>
+ * Copyright (C) 2016 Marc Kleine-Budde <mkl@pengutronix.de>
*
* Derived from:
* can_baud.c - CAN baudrate calculation
* Copyright 2005 Stanislav Marek
* email:pisa@cmp.felk.cvut.cz
*
- * This software is released under the GPL-License.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
*/
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdint.h>
#include <string.h>
-#include <getopt.h>
-#define do_div(a,b) a = (a) / (b)
+#include <linux/types.h>
+#include <linux/can/netlink.h>
+
+/* imported from kernel */
+
+/**
+ * abs - return absolute value of an argument
+ * @x: the value. If it is unsigned type, it is converted to signed type first.
+ * char is treated as if it was signed (regardless of whether it really is)
+ * but the macro's return type is preserved as char.
+ *
+ * Return: an absolute value of x.
+ */
+#define abs(x) __abs_choose_expr(x, long long, \
+ __abs_choose_expr(x, long, \
+ __abs_choose_expr(x, int, \
+ __abs_choose_expr(x, short, \
+ __abs_choose_expr(x, char, \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(typeof(x), char), \
+ (char)({ signed char __x = (x); __x<0?-__x:__x; }), \
+ ((void)0)))))))
+
+#define __abs_choose_expr(x, type, other) __builtin_choose_expr( \
+ __builtin_types_compatible_p(typeof(x), signed type) || \
+ __builtin_types_compatible_p(typeof(x), unsigned type), \
+ ({ signed type __x = (x); __x < 0 ? -__x : __x; }), other)
+
+/*
+ * min()/max()/clamp() macros that also do
+ * strict type-checking.. See the
+ * "unnecessary" pointer comparison.
+ */
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({ \
+ typeof(x) _max1 = (x); \
+ typeof(y) _max2 = (y); \
+ (void) (&_max1 == &_max2); \
+ _max1 > _max2 ? _max1 : _max2; })
+
+/**
+ * clamp - return a value clamped to a given range with strict typechecking
+ * @val: current value
+ * @lo: lowest allowable value
+ * @hi: highest allowable value
+ *
+ * This macro does strict typechecking of lo/hi to make sure they are of the
+ * same type as val. See the unnecessary pointer comparisons.
+ */
+#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi)
+
+# define do_div(n,base) ({ \
+ uint32_t __base = (base); \
+ uint32_t __rem; \
+ __rem = ((uint64_t)(n)) % __base; \
+ (n) = ((uint64_t)(n)) / __base; \
+ __rem; \
+ })
+
+/* */
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+/* we don't want to see these prints */
+#define netdev_err(dev, format, arg...) do { } while (0)
+#define netdev_warn(dev, format, arg...) do { } while (0)
-static void print_usage(char* cmd)
+/* define in-kernel-types */
+typedef __u64 u64;
+typedef __u32 u32;
+
+struct calc_bittiming_const {
+ struct can_bittiming_const bittiming_const;
+
+ __u32 ref_clk; /* CAN system clock frequency in Hz */
+ void (*printf_btr)(struct can_bittiming *bt, bool hdr);
+};
+
+/*
+ * minimal structs, just enough to be source level compatible
+ */
+struct can_priv {
+ struct can_clock clock;
+};
+
+struct net_device {
+ struct can_priv priv;
+};
+
+static inline void *netdev_priv(const struct net_device *dev)
+{
+ return (void *)&dev->priv;
+}
+
+static void print_usage(char *cmd)
{
printf("Usage: %s [options] [<CAN-contoller-name>]\n"
"\tOptions:\n"
"\t-c <clock> : real CAN system clock in Hz\n",
cmd);
- exit(1);
+ exit(EXIT_FAILURE);
}
-struct can_bittime {
- uint32_t brp;
- uint8_t prop_seg;
- uint8_t phase_seg1;
- uint8_t phase_seg2;
- uint8_t sjw;
- uint32_t tq;
- uint32_t error;
- int sampl_pt;
-};
-
-struct can_bittiming_const {
- char name[32];
- int prop_seg_min;
- int prop_seg_max;
- int phase_seg1_min;
- int phase_seg1_max;
- int phase_seg2_min;
- int phase_seg2_max;
- int sjw_max;
- int brp_min;
- int brp_max;
- int brp_inc;
- void (*printf_btr)(struct can_bittime *bt, int hdr);
-};
-
-static void printf_btr_sja1000(struct can_bittime *bt, int hdr)
+static void printf_btr_sja1000(struct can_bittiming *bt, bool hdr)
{
uint8_t btr0, btr1;
}
}
-static void printf_btr_at91(struct can_bittime *bt, int hdr)
+static void printf_btr_at91(struct can_bittiming *bt, bool hdr)
{
if (hdr) {
- printf("CAN_BR");
+ printf("%10s", "CAN_BR");
} else {
uint32_t br = ((bt->phase_seg2 - 1) |
((bt->phase_seg1 - 1) << 4) |
}
}
-static void printf_btr_mcp2510(struct can_bittime *bt, int hdr)
+static void printf_btr_flexcan(struct can_bittiming *bt, bool hdr)
+{
+ if (hdr) {
+ printf("%10s", "CAN_CTRL");
+ } else {
+ uint32_t ctrl = (((bt->brp - 1) << 24) |
+ ((bt->sjw - 1) << 22) |
+ ((bt->phase_seg1 - 1) << 19) |
+ ((bt->phase_seg2 - 1) << 16) |
+ ((bt->prop_seg - 1) << 0));
+
+ printf("0x%08x", ctrl);
+ }
+}
+
+static void printf_btr_mcp251x(struct can_bittiming *bt, bool hdr)
{
uint8_t cnf1, cnf2, cnf3;
if (hdr) {
printf("CNF1 CNF2 CNF3");
} else {
- cnf1 = ((bt->sjw - 1) << 6) | bt->brp;
+ cnf1 = ((bt->sjw - 1) << 6) | (bt->brp - 1);
cnf2 = 0x80 | ((bt->phase_seg1 - 1) << 3) | (bt->prop_seg - 1);
cnf3 = bt->phase_seg2 - 1;
printf("0x%02x 0x%02x 0x%02x", cnf1, cnf2, cnf3);
}
}
-static void printf_btr_rtcantl1(struct can_bittime *bt, int hdr)
+static void printf_btr_ti_hecc(struct can_bittiming *bt, bool hdr)
{
- uint16_t bcr0, bcr1;
+ if (hdr) {
+ printf("%10s", "CANBTC");
+ } else {
+ uint32_t can_btc;
+
+ can_btc = (bt->phase_seg2 - 1) & 0x7;
+ can_btc |= ((bt->phase_seg1 + bt->prop_seg - 1)
+ & 0xF) << 3;
+ can_btc |= ((bt->sjw - 1) & 0x3) << 8;
+ can_btc |= ((bt->brp - 1) & 0xFF) << 16;
+
+ printf("0x%08x", can_btc);
+ }
+}
+#define RCAR_CAN_BCR_TSEG1(x) (((x) & 0x0f) << 20)
+#define RCAR_CAN_BCR_BPR(x) (((x) & 0x3ff) << 8)
+#define RCAR_CAN_BCR_SJW(x) (((x) & 0x3) << 4)
+#define RCAR_CAN_BCR_TSEG2(x) ((x) & 0x07)
+
+static void printf_btr_rcar_can(struct can_bittiming *bt, bool hdr)
+{
if (hdr) {
- printf("__BCR0 __BCR1");
+ printf("%10s", "CiBCR");
} else {
- bcr1 = ((((bt->prop_seg + bt->phase_seg1 - 1) & 0x0F) << 12) |
- (((bt->phase_seg2 - 1) & 0x07) << 8) |
- (((bt->sjw - 1) & 0x03) << 4));
- bcr0 = ((bt->brp - 1) & 0xFF);
- printf("0x%04x 0x%04x", bcr0, bcr1);
+ uint32_t bcr;
+
+ bcr = RCAR_CAN_BCR_TSEG1(bt->phase_seg1 + bt->prop_seg - 1) |
+ RCAR_CAN_BCR_BPR(bt->brp - 1) |
+ RCAR_CAN_BCR_SJW(bt->sjw - 1) |
+ RCAR_CAN_BCR_TSEG2(bt->phase_seg2 - 1);
+
+ printf("0x%08x", bcr << 8);
}
}
-struct can_bittiming_const can_calc_consts[] = {
+static struct calc_bittiming_const can_calc_consts[] = {
{
- "sja1000",
- /* Note: only prop_seg + bt->phase_seg1 matters */
- .phase_seg1_min = 1,
- .phase_seg1_max = 16,
- .phase_seg2_min = 1,
- .phase_seg2_max = 8,
- .sjw_max = 4,
- .brp_min = 1,
- .brp_max = 64,
- .brp_inc = 1,
+ .bittiming_const = {
+ .name = "sja1000",
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+ },
+ .ref_clk = 8000000,
.printf_btr = printf_btr_sja1000,
- },
- {
- "mscan",
- /* Note: only prop_seg + bt->phase_seg1 matters */
- .phase_seg1_min = 4,
- .phase_seg1_max = 16,
- .phase_seg2_min = 2,
- .phase_seg2_max = 8,
- .sjw_max = 4,
- .brp_min = 1,
- .brp_max = 64,
- .brp_inc = 1,
+ }, {
+ .bittiming_const = {
+ .name = "mscan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+ },
+ .ref_clk = 32000000,
.printf_btr = printf_btr_sja1000,
- },
- {
- "at91",
- .prop_seg_min = 1,
- .prop_seg_max = 8,
- .phase_seg1_min = 1,
- .phase_seg1_max = 8,
- .phase_seg2_min = 2,
- .phase_seg2_max = 8,
- .sjw_max = 4,
- .brp_min = 1,
- .brp_max = 128,
- .brp_inc = 1,
+ }, {
+ .bittiming_const = {
+ .name = "mscan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+ },
+ .ref_clk = 33000000,
+ .printf_btr = printf_btr_sja1000,
+ }, {
+ .bittiming_const = {
+ .name = "mscan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+ },
+ .ref_clk = 33300000,
+ .printf_btr = printf_btr_sja1000,
+ }, {
+ .bittiming_const = {
+ .name = "mscan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+ },
+ .ref_clk = 33333333,
+ .printf_btr = printf_btr_sja1000,
+ }, {
+ .bittiming_const = {
+ .name = "mscan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+ },
+ .ref_clk = 66660000, /* mpc5121 */
+ .printf_btr = printf_btr_sja1000,
+ }, {
+ .bittiming_const = {
+ .name = "mscan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+ },
+ .ref_clk = 66666666, /* mpc5121 */
+ .printf_btr = printf_btr_sja1000,
+ }, {
+ .bittiming_const = {
+ .name = "at91",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 2,
+ .brp_max = 128,
+ .brp_inc = 1,
+ },
+ .ref_clk = 100000000,
.printf_btr = printf_btr_at91,
- },
- {
- "mcp2510",
- .prop_seg_min = 1,
- .prop_seg_max = 8,
- .phase_seg1_min = 1,
- .phase_seg1_max = 8,
- .phase_seg2_min = 2,
- .phase_seg2_max = 8,
- .sjw_max = 4,
- .brp_min = 1,
- .brp_max = 64,
- .brp_inc = 1,
- .printf_btr = printf_btr_mcp2510,
- },
- {
- "rtcantl1",
- .prop_seg_min = 2,
- .prop_seg_max = 8,
- .phase_seg1_min = 2,
- .phase_seg1_max = 8,
- .phase_seg2_min = 2,
- .phase_seg2_max = 8,
- .sjw_max = 4,
- .brp_min = 1,
- .brp_max = 256,
- .brp_inc = 1,
- .printf_btr = printf_btr_rtcantl1,
+ }, {
+ .bittiming_const = {
+ .name = "at91",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 2,
+ .brp_max = 128,
+ .brp_inc = 1,
+ },
+ /* real world clock as found on the ronetix PM9263 */
+ .ref_clk = 99532800,
+ .printf_btr = printf_btr_at91,
+ }, {
+ .bittiming_const = {
+ .name = "flexcan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+ },
+ .ref_clk = 24000000, /* mx28 */
+ .printf_btr = printf_btr_flexcan,
+ }, {
+ .bittiming_const = {
+ .name = "flexcan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+ },
+ .ref_clk = 30000000, /* mx6 */
+ .printf_btr = printf_btr_flexcan,
+ }, {
+ .bittiming_const = {
+ .name = "flexcan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+ },
+ .ref_clk = 49875000,
+ .printf_btr = printf_btr_flexcan,
+ }, {
+ .bittiming_const = {
+ .name = "flexcan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+ },
+ .ref_clk = 66000000,
+ .printf_btr = printf_btr_flexcan,
+ }, {
+ .bittiming_const = {
+ .name = "flexcan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+ },
+ .ref_clk = 66500000,
+ .printf_btr = printf_btr_flexcan,
+ }, {
+ .bittiming_const = {
+ .name = "flexcan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+ },
+ .ref_clk = 66666666,
+ .printf_btr = printf_btr_flexcan,
+ }, {
+ .bittiming_const = {
+ .name = "flexcan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+ },
+ .ref_clk = 83368421,
+ .printf_btr = printf_btr_flexcan, /* vybrid */
+ }, {
+ .bittiming_const = {
+ .name = "mcp251x",
+ .tseg1_min = 3,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+ },
+ .ref_clk = 8000000,
+ .printf_btr = printf_btr_mcp251x,
+ }, {
+ .bittiming_const = {
+ .name = "mcp251x",
+ .tseg1_min = 3,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+ },
+ .ref_clk = 16000000,
+ .printf_btr = printf_btr_mcp251x,
+ }, {
+ .bittiming_const = {
+ .name = "ti_hecc",
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 256,
+ .brp_inc = 1,
+ },
+ .ref_clk = 13000000,
+ .printf_btr = printf_btr_ti_hecc,
+ }, {
+ .bittiming_const = {
+ .name = "rcar_can",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+ },
+ .ref_clk = 65000000,
+ .printf_btr = printf_btr_rcar_can,
},
};
100000,
50000,
20000,
- 10000
+ 10000,
};
+#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
+#define CAN_CALC_SYNC_SEG 1
+
+/*
+ * Bit-timing calculation derived from:
+ *
+ * Code based on LinCAN sources and H8S2638 project
+ * Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
+ * Copyright 2005 Stanislav Marek
+ * email: pisa@cmp.felk.cvut.cz
+ *
+ * Calculates proper bit-timing parameters for a specified bit-rate
+ * and sample-point, which can then be used to set the bit-timing
+ * registers of the CAN controller. You can find more information
+ * in the header file linux/can/netlink.h.
+ */
static int can_update_spt(const struct can_bittiming_const *btc,
- int sampl_pt, int tseg, int *tseg1, int *tseg2)
+ unsigned int spt_nominal, unsigned int tseg,
+ unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
+ unsigned int *spt_error_ptr)
{
- *tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000;
- if (*tseg2 < btc->phase_seg2_min)
- *tseg2 = btc->phase_seg2_min;
- if (*tseg2 > btc->phase_seg2_max)
- *tseg2 = btc->phase_seg2_max;
- *tseg1 = tseg - *tseg2;
- if (*tseg1 > btc->prop_seg_max + btc->phase_seg1_max) {
- *tseg1 = btc->prop_seg_max + btc->phase_seg1_max;
- *tseg2 = tseg - *tseg1;
+ unsigned int spt_error, best_spt_error = UINT_MAX;
+ unsigned int spt, best_spt = 0;
+ unsigned int tseg1, tseg2;
+ int i;
+
+ for (i = 0; i <= 1; i++) {
+ tseg2 = tseg + CAN_CALC_SYNC_SEG - (spt_nominal * (tseg + CAN_CALC_SYNC_SEG)) / 1000 - i;
+ tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
+ tseg1 = tseg - tseg2;
+ if (tseg1 > btc->tseg1_max) {
+ tseg1 = btc->tseg1_max;
+ tseg2 = tseg - tseg1;
+ }
+
+ spt = 1000 * (tseg + CAN_CALC_SYNC_SEG - tseg2) / (tseg + CAN_CALC_SYNC_SEG);
+ spt_error = abs(spt_nominal - spt);
+
+ if ((spt <= spt_nominal) && (spt_error < best_spt_error)) {
+ best_spt = spt;
+ best_spt_error = spt_error;
+ *tseg1_ptr = tseg1;
+ *tseg2_ptr = tseg2;
+ }
}
- return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
+
+ if (spt_error_ptr)
+ *spt_error_ptr = best_spt_error;
+
+ return best_spt;
}
-int can_calc_bittiming(struct can_bittime *bt, long bitrate,
- int sampl_pt, long clock,
- const struct can_bittiming_const *btc)
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
+ const struct can_bittiming_const *btc)
{
- long best_error = 1000000000, error;
- int best_tseg = 0, best_brp = 0, brp = 0;
- int spt_error = 1000, spt = 0;
- long rate, best_rate = 0;
- int tseg = 0, tseg1 = 0, tseg2 = 0;
- uint64_t v64;
-
- if (sampl_pt == 0) {
- /* Use CIA recommended sample points */
- if (bitrate > 800000)
- sampl_pt = 750;
- else if (bitrate > 500000)
- sampl_pt = 800;
+ struct can_priv *priv = netdev_priv(dev);
+ unsigned int rate; /* current bitrate */
+ unsigned int rate_error; /* difference between current and nominal value */
+ unsigned int best_rate_error = UINT_MAX;
+ unsigned int spt_error; /* difference between current and nominal value */
+ unsigned int best_spt_error = UINT_MAX;
+ unsigned int spt_nominal; /* nominal sample point */
+ unsigned int best_tseg = 0; /* current best value for tseg */
+ unsigned int best_brp = 0; /* current best value for brp */
+ unsigned int brp, tsegall, tseg, tseg1, tseg2;
+ u64 v64;
+
+ /* Use CiA recommended sample points */
+ if (bt->sample_point) {
+ spt_nominal = bt->sample_point;
+ } else {
+ if (bt->bitrate > 800000)
+ spt_nominal = 750;
+ else if (bt->bitrate > 500000)
+ spt_nominal = 800;
else
- sampl_pt = 875;
+ spt_nominal = 875;
}
-#ifdef DEBUG
- printf("tseg brp bitrate biterror\n");
-#endif
-
/* tseg even = round down, odd = round up */
- for (tseg = (btc->prop_seg_max + btc->phase_seg1_max +
- btc->phase_seg2_max) * 2 + 1;
- tseg >= (btc->prop_seg_min + btc->phase_seg1_min +
- btc->phase_seg2_min) * 2; tseg--) {
- /* Compute all posibilities of tseg choices (tseg=tseg1+tseg2) */
- brp = clock / ((1 + tseg / 2) * bitrate) + tseg % 2;
- /* chose brp step which is possible in system */
+ for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
+ tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
+ tsegall = CAN_CALC_SYNC_SEG + tseg / 2;
+
+ /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
+ brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
+
+ /* choose brp step which is possible in system */
brp = (brp / btc->brp_inc) * btc->brp_inc;
if ((brp < btc->brp_min) || (brp > btc->brp_max))
continue;
- rate = clock / (brp * (1 + tseg / 2));
- error = bitrate - rate;
+
+ rate = priv->clock.freq / (brp * tsegall);
+ rate_error = abs(bt->bitrate - rate);
+
/* tseg brp biterror */
-#if DEBUG
- printf("%4d %3d %7ld %8ld %03d\n", tseg, brp, rate, error,
- can_update_spt(btc, sampl_pt, tseg / 2,
- &tseg1, &tseg2));
-#endif
- if (error < 0)
- error = -error;
- if (error > best_error)
+ if (rate_error > best_rate_error)
continue;
- best_error = error;
- if (error == 0) {
- spt = can_update_spt(btc, sampl_pt, tseg / 2,
- &tseg1, &tseg2);
- error = sampl_pt - spt;
- //printf("%d %d %d\n", sampl_pt, error, spt_error);
- if (error < 0)
- error = -error;
- if (error > spt_error)
- continue;
- spt_error = error;
- //printf("%d\n", spt_error);
- }
- //printf("error=%d\n", best_error);
+
+ /* reset sample point error if we have a better bitrate */
+ if (rate_error < best_rate_error)
+ best_spt_error = UINT_MAX;
+
+ can_update_spt(btc, spt_nominal, tseg / 2, &tseg1, &tseg2, &spt_error);
+ if (spt_error > best_spt_error)
+ continue;
+
+ best_spt_error = spt_error;
+ best_rate_error = rate_error;
best_tseg = tseg / 2;
best_brp = brp;
- best_rate = rate;
- if (error == 0)
+
+ if (rate_error == 0 && spt_error == 0)
break;
}
- if (best_error && (bitrate / best_error < 10))
- return -1;
+ if (best_rate_error) {
+ /* Error in one-tenth of a percent */
+ rate_error = (best_rate_error * 1000) / bt->bitrate;
+ if (rate_error > CAN_CALC_MAX_ERROR) {
+ netdev_err(dev,
+ "bitrate error %ld.%ld%% too high\n",
+ rate_error / 10, rate_error % 10);
+ return -EDOM;
+ }
+ netdev_warn(dev, "bitrate error %ld.%ld%%\n",
+ rate_error / 10, rate_error % 10);
+ }
+
+ /* real sample point */
+ bt->sample_point = can_update_spt(btc, spt_nominal, best_tseg,
+ &tseg1, &tseg2, NULL);
- spt = can_update_spt(btc, sampl_pt, best_tseg,
- &tseg1, &tseg2);
+ v64 = (u64)best_brp * 1000 * 1000 * 1000;
+ do_div(v64, priv->clock.freq);
+ bt->tq = (u32)v64;
+ bt->prop_seg = tseg1 / 2;
+ bt->phase_seg1 = tseg1 - bt->prop_seg;
+ bt->phase_seg2 = tseg2;
- if (tseg2 > tseg1) {
- /* sample point < 50% */
- bt->phase_seg1 = tseg1 / 2;
+ /* check for sjw user settings */
+ if (!bt->sjw || !btc->sjw_max) {
+ bt->sjw = 1;
} else {
- /* keep phase_seg{1,2} equal around the sample point */
- bt->phase_seg1 = tseg2;
- }
- bt->prop_seg = tseg1 - bt->phase_seg1;
- /* Check prop_seg range if necessary */
- if (btc->prop_seg_min || btc->prop_seg_max) {
- if (bt->prop_seg < btc->prop_seg_min)
- bt->prop_seg = btc->prop_seg_min;
- else if (bt->prop_seg > btc->prop_seg_max)
- bt->prop_seg = btc->prop_seg_max;
- bt->phase_seg1 = tseg1 - bt->prop_seg;
+ /* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
+ if (bt->sjw > btc->sjw_max)
+ bt->sjw = btc->sjw_max;
+ /* bt->sjw must not be higher than tseg2 */
+ if (tseg2 < bt->sjw)
+ bt->sjw = tseg2;
}
- bt->phase_seg2 = tseg2;
- bt->sjw = 1;
+
bt->brp = best_brp;
- bt->error = best_error;
- bt->sampl_pt = spt;
- v64 = (uint64_t)bt->brp * 1000000000UL;
- v64 /= clock;
- bt->tq = (int)v64;
+
+ /* real bit-rate */
+ bt->bitrate = priv->clock.freq / (bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2));
return 0;
}
-void print_bit_timing(const struct can_bittiming_const *btc,
- long bitrate, int sampl_pt, long ref_clk, int quiet)
+static __u32 get_cia_sample_point(__u32 bitrate)
{
- struct can_bittime bt;
+ __u32 sampl_pt;
+
+ if (bitrate > 800000)
+ sampl_pt = 750;
+ else if (bitrate > 500000)
+ sampl_pt = 800;
+ else
+ sampl_pt = 875;
- memset(&bt, 0, sizeof(bt));
+ return sampl_pt;
+}
+
+static void print_bit_timing(const struct calc_bittiming_const *btc,
+ __u32 bitrate, __u32 sample_point, __u32 ref_clk,
+ bool quiet)
+{
+ struct net_device dev = {
+ .priv.clock.freq = ref_clk,
+ };
+ struct can_bittiming bt = {
+ .bitrate = bitrate,
+ .sample_point = sample_point,
+ };
+ long rate_error, spt_error;
if (!quiet) {
- printf("Bit timing parameters for %s using %ldHz\n",
- btc->name, ref_clk);
- printf("Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP SampP Error ");
- btc->printf_btr(&bt, 1);
+ printf("Bit timing parameters for %s with %.6f MHz ref clock\n"
+ "nominal real Bitrt nom real SampP\n"
+ "Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP Bitrate Error SampP SampP Error ",
+ btc->bittiming_const.name,
+ ref_clk / 1000000.0);
+
+ btc->printf_btr(&bt, true);
printf("\n");
}
- if (can_calc_bittiming(&bt, bitrate, sampl_pt, ref_clk, btc)) {
- printf("%7ld ***bitrate not possible***\n", bitrate);
+ if (can_calc_bittiming(&dev, &bt, &btc->bittiming_const)) {
+ printf("%7d ***bitrate not possible***\n", bitrate);
return;
}
- printf("%7ld %6d %3d %4d %4d %3d %3d %2d.%d%% %4.1f%% ",
- bitrate, bt.tq, bt.prop_seg, bt.phase_seg1,
- bt.phase_seg2, bt.sjw, bt.brp,
- bt.sampl_pt / 10, bt.sampl_pt % 10,
- (double)100 * bt.error / bitrate);
- btc->printf_btr(&bt, 0);
+ /* get nominal sample point */
+ if (!sample_point)
+ sample_point = get_cia_sample_point(bitrate);
+
+ rate_error = abs(bitrate - bt.bitrate);
+ spt_error = abs(sample_point - bt.sample_point);
+
+ printf("%7d "
+ "%6d %3d %4d %4d "
+ "%3d %3d "
+ "%7d %4.1f%% "
+ "%4.1f%% %4.1f%% %4.1f%% ",
+ bitrate,
+ bt.tq, bt.prop_seg, bt.phase_seg1, bt.phase_seg2,
+ bt.sjw, bt.brp,
+
+ bt.bitrate,
+ 100.0 * rate_error / bitrate,
+
+ sample_point / 10.0,
+ bt.sample_point / 10.0,
+ 100.0 * spt_error / sample_point);
+
+ btc->printf_btr(&bt, false);
printf("\n");
}
+static void do_list(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++)
+ printf("%s\n", can_calc_consts[i].bittiming_const.name);
+}
+
int main(int argc, char *argv[])
{
- long bitrate = 0;
- long ref_clk = 8000000;
- int sampl_pt = 0;
- int quiet = 0;
- int list = 0;
+ __u32 bitrate = 0;
+ __u32 opt_ref_clk = 0, ref_clk;
+ unsigned int spt_nominal = 0;
+ bool quiet = false, list = false, found = false;
char *name = NULL;
- int i, opt;
+ unsigned int i, j;
+ int opt;
- const struct can_bittiming_const *btc = NULL;
+ const struct calc_bittiming_const *btc = NULL;
while ((opt = getopt(argc, argv, "b:c:lps:")) != -1) {
switch (opt) {
break;
case 'c':
- ref_clk = atoi(optarg);
+ opt_ref_clk = strtoul(optarg, NULL, 10);
break;
case 'l':
- list = 1;
+ list = true;
break;
case 'q':
- quiet = 1;
+ quiet = true;
break;
case 's':
- sampl_pt = atoi(optarg);
+ spt_nominal = strtoul(optarg, NULL, 10);
break;
default:
name = argv[optind];
if (list) {
- for (i = 0; i < sizeof(can_calc_consts) /
- sizeof(struct can_bittiming_const); i++)
- printf("%s\n", can_calc_consts[i].name);
- return 0;
+ do_list();
+ exit(EXIT_SUCCESS);
}
- if (sampl_pt && (sampl_pt >= 1000 || sampl_pt < 100))
+ if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100))
print_usage(argv[0]);
- if (name) {
- for (i = 0; i < sizeof(can_calc_consts) /
- sizeof(struct can_bittiming_const); i++) {
- if (!strcmp(can_calc_consts[i].name, name)) {
- btc = &can_calc_consts[i];
- break;
- }
- }
- if (!btc)
- print_usage(argv[0]);
+ for (i = 0; i < ARRAY_SIZE(can_calc_consts); i++) {
+ if (name && strcmp(can_calc_consts[i].bittiming_const.name, name))
+ continue;
- } else {
- btc = &can_calc_consts[0];
+ found = true;
+ btc = &can_calc_consts[i];
+
+ if (opt_ref_clk)
+ ref_clk = opt_ref_clk;
+ else
+ ref_clk = btc->ref_clk;
+
+ if (bitrate) {
+ print_bit_timing(btc, bitrate, spt_nominal, ref_clk, quiet);
+ } else {
+ for (j = 0; j < ARRAY_SIZE(common_bitrates); j++)
+ print_bit_timing(btc, common_bitrates[j],
+ spt_nominal, ref_clk, j);
+ }
+ printf("\n");
}
- if (bitrate) {
- print_bit_timing(btc, bitrate, sampl_pt, ref_clk, quiet);
- } else {
- for (i = 0; i < sizeof(common_bitrates) / sizeof(long); i++)
- print_bit_timing(btc, common_bitrates[i], sampl_pt,
- ref_clk, i);
+ if (!found) {
+ printf("error: unknown CAN controller '%s', try one of these:\n\n", name);
+ do_list();
+ exit(EXIT_FAILURE);
}
- return 0;
+ exit(EXIT_SUCCESS);
}