* 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>
#define ENOTSUPP 524 /* Operation is not supported */
#endif
-/* usefull defines */
+/* useful defines */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define do_div(a,b) a = (a) / (b)
__u32 brp_inc;
/* added for can-calc-bit-timing utility */
+ __u32 ref_clk; /* CAN system clock frequency in Hz */
void (*printf_btr)(struct can_bittiming *bt, int hdr);
};
"\t-c <clock> : real CAN system clock in Hz\n",
cmd);
- exit(1);
+ exit(EXIT_FAILURE);
}
static void printf_btr_sja1000(struct can_bittiming *bt, int hdr)
static void printf_btr_at91(struct can_bittiming *bt, int 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_flexcan(struct can_bittiming *bt, int 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, int 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_bittiming *bt, int hdr)
+static void printf_btr_ti_hecc(struct can_bittiming *bt, int hdr)
{
- uint16_t bcr0, bcr1;
-
if (hdr) {
- printf("__BCR0 __BCR1");
+ printf("%10s", "CANBTC");
} 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 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);
}
}
.brp_max = 64,
.brp_inc = 1,
+ .ref_clk = 8000000,
.printf_btr = printf_btr_sja1000,
},
{
.brp_max = 64,
.brp_inc = 1,
+ .ref_clk = 32000000,
.printf_btr = printf_btr_sja1000,
},
{
+ .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,
+ },
+ {
+ .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,
+ },
+ {
+ .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,
+ },
+ {
+ .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,
+ },
+ {
+ .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,
+ },
+ {
.name = "at91",
.tseg1_min = 4,
.tseg1_max = 16,
.brp_max = 128,
.brp_inc = 1,
+ /* real world clock as found on the ronetix PM9263 */
+ .ref_clk = 99532800,
.printf_btr = printf_btr_at91,
},
{
+ .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,
+ },
+ {
+ .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,
+ },
+ {
+ .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,
+ },
+ {
+ .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,
+ },
+ {
.name = "mcp251x",
.tseg1_min = 3,
.tseg1_max = 16,
.brp_max = 64,
.brp_inc = 1,
+ .ref_clk = 8000000,
.printf_btr = printf_btr_mcp251x,
},
{
- .name = "rtcantl1",
- .tseg1_min = 4,
+ .name = "mcp251x",
+ .tseg1_min = 3,
.tseg1_max = 16,
.tseg2_min = 2,
.tseg2_max = 8,
.sjw_max = 4,
.brp_min = 1,
- .brp_max = 256,
+ .brp_max = 64,
.brp_inc = 1,
- .printf_btr = printf_btr_rtcantl1,
+ .ref_clk = 16000000,
+ .printf_btr = printf_btr_mcp251x,
},
+ {
+ .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,
+ }
};
static long common_bitrates[] = {
{
struct can_priv *priv = netdev_priv(dev);
const struct can_bittiming_const *btc = priv->bittiming_const;
- long rate, best_rate = 0;
+ long rate = 0;
long best_error = 1000000000, error = 0;
int best_tseg = 0, best_brp = 0, brp = 0;
int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
}
best_tseg = tseg / 2;
best_brp = brp;
- best_rate = rate;
if (error == 0)
break;
}
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 can_bittiming_const *btc,
__u32 bitrate, __u32 sample_point, __u32 ref_clk,
int quiet)
.bitrate = bitrate,
.sample_point = sample_point,
};
- long rate_error;
+ long rate_error, spt_error;
if (!quiet) {
- printf("Bit timing parameters for %s using %dHz\n",
- btc->name, ref_clk);
- printf("Bitrate TQ[ns] PrS PhS1 PhS2 SJW BRP SampP Error ");
+ 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->name,
+ ref_clk / 1000000.0);
+
btc->printf_btr(&bt, 1);
printf("\n");
}
return;
}
+ /* get nominal sample point */
+ if (!sample_point)
+ sample_point = get_cia_sample_point(bitrate);
+
rate_error = abs((__s32)(bitrate - bt.bitrate));
+ spt_error = abs((__s32)(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);
- printf("%7d %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.sample_point / 10, bt.sample_point % 10,
- 100.0 * rate_error / bitrate);
btc->printf_btr(&bt, 0);
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].name);
+}
+
int main(int argc, char *argv[])
{
- long bitrate = 0;
- long ref_clk = 8000000;
+ __u32 bitrate = 0;
+ __u32 opt_ref_clk = 0, ref_clk;
int sampl_pt = 0;
int quiet = 0;
int list = 0;
char *name = NULL;
- int i, opt;
+ unsigned int i, j;
+ int opt, found = 0;
const struct can_bittiming_const *btc = NULL;
break;
case 'c':
- ref_clk = atoi(optarg);
+ opt_ref_clk = atoi(optarg);
break;
case 'l':
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))
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].name, name))
+ continue;
- } else {
- btc = &can_calc_consts[0];
+ found = 1;
+ 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, sampl_pt, ref_clk, quiet);
+ } else {
+ for (j = 0; j < ARRAY_SIZE(common_bitrates); j++)
+ print_bit_timing(btc, common_bitrates[j],
+ sampl_pt, 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);
}