123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722 |
- /* 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
- * 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
- *
- * 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 <string.h>
- #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)
- /* define in-kernel-types */
- typedef __u64 u64;
- typedef __u32 u32;
- struct calc_ref_clk {
- __u32 clk; /* CAN system clock frequency in Hz */
- char *name;
- };
- struct calc_bittiming_const {
- struct can_bittiming_const bittiming_const;
- const struct calc_ref_clk ref_clk[16];
- 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-q : don't print header line\n"
- "\t-l : list all support CAN controller names\n"
- "\t-b <bitrate> : bit-rate in bits/sec\n"
- "\t-s <samp_pt> : sample-point in one-tenth of a percent\n"
- "\t or 0 for CIA recommended sample points\n"
- "\t-c <clock> : real CAN system clock in Hz\n",
- cmd);
- exit(EXIT_FAILURE);
- }
- static void printf_btr_sja1000(struct can_bittiming *bt, bool hdr)
- {
- uint8_t btr0, btr1;
- if (hdr) {
- printf("BTR0 BTR1");
- } else {
- btr0 = ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
- btr1 = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
- (((bt->phase_seg2 - 1) & 0x7) << 4);
- printf("0x%02x 0x%02x", btr0, btr1);
- }
- }
- static void printf_btr_at91(struct can_bittiming *bt, bool hdr)
- {
- if (hdr) {
- printf("%10s", "CAN_BR");
- } else {
- uint32_t br = ((bt->phase_seg2 - 1) |
- ((bt->phase_seg1 - 1) << 4) |
- ((bt->prop_seg - 1) << 8) |
- ((bt->sjw - 1) << 12) |
- ((bt->brp - 1) << 16));
- printf("0x%08x", br);
- }
- }
- 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 - 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_ti_hecc(struct can_bittiming *bt, bool hdr)
- {
- 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("%10s", "CiBCR");
- } else {
- 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);
- }
- }
- static struct calc_bittiming_const can_calc_consts[] = {
- {
- .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 = {
- { .clk = 8000000, },
- },
- .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 = {
- { .clk = 32000000, },
- { .clk = 33000000, },
- { .clk = 33300000, },
- { .clk = 33333333, },
- { .clk = 66660000, .name = "mpc5121", },
- { .clk = 66666666, .name = "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 = {
- { .clk = 99532800, .name = "ronetix PM9263", },
- { .clk = 100000000, },
- },
- .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 = {
- { .clk = 24000000, .name = "mx28" },
- { .clk = 30000000, .name = "mx6" },
- { .clk = 49875000, },
- { .clk = 66000000, },
- { .clk = 66500000, },
- { .clk = 66666666, },
- { .clk = 83368421, .name = "vybrid" },
- },
- .printf_btr = printf_btr_flexcan,
- }, {
- .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 = {
- { .clk = 8000000, },
- { .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 = {
- { .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 = {
- { .clk = 65000000, },
- },
- .printf_btr = printf_btr_rcar_can,
- },
- };
- static long common_bitrates[] = {
- 1000000,
- 800000,
- 500000,
- 250000,
- 125000,
- 100000,
- 50000,
- 20000,
- 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,
- unsigned int spt_nominal, unsigned int tseg,
- unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
- unsigned int *spt_error_ptr)
- {
- 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;
- }
- }
- if (spt_error_ptr)
- *spt_error_ptr = best_spt_error;
- return best_spt;
- }
- static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
- const struct can_bittiming_const *btc)
- {
- 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
- spt_nominal = 875;
- }
- /* tseg even = round down, odd = round up */
- 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 = priv->clock.freq / (brp * tsegall);
- rate_error = abs(bt->bitrate - rate);
- /* tseg brp biterror */
- if (rate_error > best_rate_error)
- continue;
- /* 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;
- if (rate_error == 0 && spt_error == 0)
- break;
- }
- 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);
- 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;
- /* check for sjw user settings */
- if (!bt->sjw || !btc->sjw_max) {
- bt->sjw = 1;
- } else {
- /* 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->brp = best_brp;
- /* real bit-rate */
- bt->bitrate = priv->clock.freq / (bt->brp * (CAN_CALC_SYNC_SEG + tseg1 + tseg2));
- return 0;
- }
- static __u32 get_cia_sample_point(__u32 bitrate)
- {
- __u32 sampl_pt;
- if (bitrate > 800000)
- sampl_pt = 750;
- else if (bitrate > 500000)
- sampl_pt = 800;
- else
- sampl_pt = 875;
- return sampl_pt;
- }
- static void print_bit_timing(const struct calc_bittiming_const *btc,
- const struct calc_ref_clk *ref_clk,
- unsigned int bitrate_nominal,
- unsigned int spt_nominal,
- bool quiet)
- {
- struct net_device dev = {
- .priv.clock.freq = ref_clk->clk,
- };
- struct can_bittiming bt = {
- .bitrate = bitrate_nominal,
- .sample_point = spt_nominal,
- };
- long rate_error, spt_error;
- if (!quiet) {
- printf("Bit timing parameters for %s%s%s%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->name ? " (" : "",
- ref_clk->name ? ref_clk->name : "",
- ref_clk->name ? ")" : "",
- ref_clk->clk / 1000000.0);
- btc->printf_btr(&bt, true);
- printf("\n");
- }
- if (can_calc_bittiming(&dev, &bt, &btc->bittiming_const)) {
- printf("%7d ***bitrate not possible***\n", bitrate_nominal);
- return;
- }
- /* get nominal sample point */
- if (!spt_nominal)
- spt_nominal = get_cia_sample_point(bitrate_nominal);
- rate_error = abs(bitrate_nominal - bt.bitrate);
- spt_error = abs(spt_nominal - bt.sample_point);
- printf("%7d "
- "%6d %3d %4d %4d "
- "%3d %3d "
- "%7d %4.1f%% "
- "%4.1f%% %4.1f%% %4.1f%% ",
- bitrate_nominal,
- bt.tq, bt.prop_seg, bt.phase_seg1, bt.phase_seg2,
- bt.sjw, bt.brp,
- bt.bitrate,
- 100.0 * rate_error / bitrate_nominal,
- spt_nominal / 10.0,
- bt.sample_point / 10.0,
- 100.0 * spt_error / spt_nominal);
- 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[])
- {
- __u32 bitrate_nominal = 0;
- struct calc_ref_clk opt_ref_clk = {
- .name = "cmd-line",
- };
- const struct calc_ref_clk *ref_clk;
- unsigned int spt_nominal = 0;
- bool quiet = false, list = false, found = false;
- char *name = NULL;
- unsigned int i, j, k;
- int opt;
- const struct calc_bittiming_const *btc;
- while ((opt = getopt(argc, argv, "b:c:lqs:")) != -1) {
- switch (opt) {
- case 'b':
- bitrate_nominal = atoi(optarg);
- break;
- case 'c':
- opt_ref_clk.clk = strtoul(optarg, NULL, 10);
- break;
- case 'l':
- list = true;
- break;
- case 'q':
- quiet = true;
- break;
- case 's':
- spt_nominal = strtoul(optarg, NULL, 10);
- break;
- default:
- print_usage(argv[0]);
- break;
- }
- }
- if (argc > optind + 1)
- print_usage(argv[0]);
- if (argc == optind + 1)
- name = argv[optind];
- if (list) {
- do_list();
- exit(EXIT_SUCCESS);
- }
- if (spt_nominal && (spt_nominal >= 1000 || spt_nominal < 100))
- 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;
- found = true;
- btc = &can_calc_consts[i];
- for (j = 0; j < ARRAY_SIZE(btc->ref_clk); j++) {
- if (opt_ref_clk.clk)
- ref_clk = &opt_ref_clk;
- else
- ref_clk = &btc->ref_clk[j];
- if (!ref_clk->clk)
- break;
- if (bitrate_nominal) {
- print_bit_timing(btc, ref_clk, bitrate_nominal,
- spt_nominal, quiet);
- } else {
- for (k = 0; k < ARRAY_SIZE(common_bitrates); k++)
- print_bit_timing(btc, ref_clk,
- common_bitrates[k],
- spt_nominal, k);
- }
- printf("\n");
- if (opt_ref_clk.clk)
- break;
- }
- }
- if (!found) {
- printf("error: unknown CAN controller '%s', try one of these:\n\n", name);
- do_list();
- exit(EXIT_FAILURE);
- }
- exit(EXIT_SUCCESS);
- }
|