/* SPDX-License-Identifier: BSD-2-Clause */ /** * @file * * @ingroup can * * @brief Common CAN baud-rate routines for OCCAN/GRCAN/GRCANFD controllers * * Implements common routines for calculating CAN baud-rate parameters from * a user provided baud-rate speed. */ /* * Copyright (C) 2019, 2020 Cobham Gailer AB * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include /*#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, tmp, 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 */ tmp = ((br->divfactor + tseg) * baud); sc = (core_hz * 2)/ tmp - core_hz / tmp; 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; }