Reimplemented the baud-rate algorithm from scratch to cope with GRCAN, GRCANFD and OC_CAN devices. --- bsps/headers.am | 1 + bsps/include/grlib/canbtrs.h | 62 +++++++++++++++++++++ bsps/shared/grlib-sources.am | 1 + bsps/shared/grlib/can/canbtrs.c | 116 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 180 insertions(+) create mode 100644 bsps/include/grlib/canbtrs.h create mode 100644 bsps/shared/grlib/can/canbtrs.c
diff --git a/bsps/headers.am b/bsps/headers.am index 5af7e43..2c9b31d 100644 --- a/bsps/headers.am +++ b/bsps/headers.am @@ -34,6 +34,7 @@ include_grlib_HEADERS += ../../bsps/include/grlib/apbuart_termios.h include_grlib_HEADERS += ../../bsps/include/grlib/b1553brm.h include_grlib_HEADERS += ../../bsps/include/grlib/b1553rt.h include_grlib_HEADERS += ../../bsps/include/grlib/bspcommon.h +include_grlib_HEADERS += ../../bsps/include/grlib/canbtrs.h include_grlib_HEADERS += ../../bsps/include/grlib/canmux.h include_grlib_HEADERS += ../../bsps/include/grlib/cons.h include_grlib_HEADERS += ../../bsps/include/grlib/debug_defs.h diff --git a/bsps/include/grlib/canbtrs.h b/bsps/include/grlib/canbtrs.h new file mode 100644 index 0000000..1fbbbfc --- /dev/null +++ b/bsps/include/grlib/canbtrs.h @@ -0,0 +1,62 @@ +/** + * @file + * @ingroup can + * @brief CAN baud-rate paramter operations for OCCAN/GRCAN/GRCANFD controllers + */ + +/* + * COPYRIGHT (c) 2019. + * Cobham Gaisler AB. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef __GRLIB_CANBTRS_H__ +#define __GRLIB_CANBTRS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* CAN Baud-rate parameters, range of valid parameter values */ +struct grlib_canbtrs_ranges { + unsigned int max_scaler; + char has_bpr; + unsigned char divfactor; + unsigned char min_tseg1; + unsigned char max_tseg1; + unsigned char min_tseg2; + unsigned char max_tseg2; +}; + +struct grlib_canbtrs_timing { + unsigned char scaler; + unsigned char ps1; + unsigned char ps2; + unsigned char rsj; + unsigned char bpr; +}; + +/* Calculate CAN baud-rate generation parameters from requested baud-rate + * + * \param baud The CAN baud rate requested + * \param core_hz Input clock [Hz] to CAN core + * \param sampl_pt CAN sample point in %, 80 means 80% + * \param br CAN Baud-rate parameters limitations + * \param timing result is placed here + */ +int grlib_canbtrs_calc_timing( + unsigned int baud, + unsigned int core_hz, + unsigned int sampl_pt, + struct grlib_canbtrs_ranges *br, + struct grlib_canbtrs_timing *timing + ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bsps/shared/grlib-sources.am b/bsps/shared/grlib-sources.am index 512a48c..f2ad1bf 100644 --- a/bsps/shared/grlib-sources.am +++ b/bsps/shared/grlib-sources.am @@ -20,6 +20,7 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/ascs/grascs.c librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/gptimer.c librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/tlib.c librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/tlib_ckinit.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/canbtrs.c librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/canmux.c librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcan.c librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/occan.c diff --git a/bsps/shared/grlib/can/canbtrs.c b/bsps/shared/grlib/can/canbtrs.c new file mode 100644 index 0000000..8600e2b --- /dev/null +++ b/bsps/shared/grlib/can/canbtrs.c @@ -0,0 +1,116 @@ +/* + * GRLIB common CAN baud-rate to timing parameters conversion + * + * COPYRIGHT (c) 2019. + * Cobham Gaisler AB. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <grlib/canbtrs.h> + +/*#define GRLIB_CANBTRS_DEBUG*/ + +/* Calculate CAN baud-rate generation parameters from requested baud-rate */ +int grlib_canbtrs_calc_timing( + unsigned int baud, + unsigned int core_hz, + unsigned int sampl_pt, + struct grlib_canbtrs_ranges *br, + struct grlib_canbtrs_timing *timing + ) +{ + int best_error = 2000000000, best_tseg=0, best_scaler=0; + int tseg=0, tseg1=0, tseg2=0, sc, error; + + /* Default to 80% sample point */ + if ((sampl_pt < 50) || (sampl_pt > 99)) + sampl_pt = 80; + + /* step though all TSEG1+TSEG2 values possible */ + for (tseg = (br->min_tseg1 + br->min_tseg2); + tseg <= (br->max_tseg1 + br->max_tseg2); + tseg++) { + /* calculate scaler */ + sc = core_hz / ((br->divfactor + tseg) * baud); + if (sc <= 0 || sc > br->max_scaler) + continue; + if (br->has_bpr && + (((sc > 256 * 1) && (sc <= 256 * 2) && (sc & 0x1)) || + ((sc > 256 * 2) && (sc <= 256 * 4) && (sc & 0x3)) || + ((sc > 256 * 4) && (sc <= 256 * 8) && (sc & 0x7)))) + continue; + + error = baud - core_hz / (sc * (br->divfactor + tseg)); +#ifdef GRLIB_CANBTRS_DEBUG + printf(" baud=%d, tseg=%d, sc=%d, error=%d\n", + baud, tseg, sc, error); +#endif + if (error < 0) + error = -error; + + /* tseg is increasing, so we accept higher tseg with the same + * baudrate to get better sampling point. + */ + if (error <= best_error) { + best_error = error; + best_tseg = tseg; + best_scaler = sc; +#ifdef GRLIB_CANBTRS_DEBUG + printf(" ! best baud=%d\n", + core_hz/(sc * (br->divfactor + tseg))); +#endif + } + } + + /* return an error if 5% off baud-rate */ + if (best_error && (baud / best_error <= 5)) { + return -2; + } else if (!timing) { + return 0; /* nothing to store result in, but a valid bitrate can be calculated */ + } + + tseg2 = (best_tseg + br->divfactor) - + ((sampl_pt * (best_tseg + br->divfactor)) / 100); + if (tseg2 < br->min_tseg2) { + tseg2 = br->min_tseg2; + } else if (tseg2 > br->max_tseg2) { + tseg2 = br->max_tseg2; + } + + tseg1 = best_tseg - tseg2; + if (tseg1 > br->max_tseg1) { + tseg1 = br->max_tseg1; + tseg2 = best_tseg - tseg1; + } else if (tseg1 < br->min_tseg1) { + tseg1 = br->min_tseg1; + tseg2 = best_tseg - tseg1; + } + + /* Get scaler and BPR from pseudo SCALER clock */ + if (best_scaler <= 256) { + timing->scaler = best_scaler - 1; + timing->bpr = 0; + } else if (best_scaler <= 256 * 2) { + timing->scaler = ((best_scaler + 1) >> 1) - 1; + timing->bpr = 1; + } else if (best_scaler <= 256 * 4) { + timing->scaler = ((best_scaler + 1) >> 2) - 1; + timing->bpr = 2; + } else { + timing->scaler = ((best_scaler + 1) >> 3) - 1; + timing->bpr = 3; + } + + timing->ps1 = tseg1; + timing->ps2 = tseg2; + timing->rsj = 1; + +#ifdef GRLIB_CANBTRS_DEBUG + printf(" ! result: sc=%d,bpr=%d,ps1=%d,ps2=%d\n", timing->scaler, timing->bpr, timing->ps1, timing->ps2); +#endif + + return 0; +} -- 2.7.4 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel