[PATCH 10/26] leon, occan: use common CAN baud-rate calculation routine
Daniel Hellstrom
daniel at gaisler.com
Mon Jun 29 11:27:57 UTC 2020
---
bsps/shared/grlib/can/occan.c | 151 ++++++++++++------------------------------
1 file changed, 41 insertions(+), 110 deletions(-)
diff --git a/bsps/shared/grlib/can/occan.c b/bsps/shared/grlib/can/occan.c
index 59b4f23..01537f9 100644
--- a/bsps/shared/grlib/can/occan.c
+++ b/bsps/shared/grlib/can/occan.c
@@ -19,6 +19,7 @@
#include <drvmgr/drvmgr.h>
#include <grlib/ambapp_bus.h>
#include <grlib/occan.h>
+#include <grlib/canbtrs.h>
#include <grlib/grlib_impl.h>
@@ -185,19 +186,20 @@ typedef struct {
#define pelican_regs pelican32_regs
#endif
+/* Default sampling point in % */
+#define OCCAN_SAMPLING_POINT 90
+
+/* OCCAN baud-rate paramter boundaries */
+struct grlib_canbtrs_ranges occan_btrs_ranges = {
+ .max_scaler = 64,
+ .has_bpr = 0,
+ .divfactor = 1,
+ .min_tseg1 = 1,
+ .max_tseg1 = 16,
+ .min_tseg2 = 1,
+ .max_tseg2 = 8,
+};
-#define MAX_TSEG2 7
-#define MAX_TSEG1 15
-
-#if 0
-typedef struct {
- unsigned char brp;
- unsigned char sjw;
- unsigned char tseg1;
- unsigned char tseg2;
- unsigned char sam;
-} occan_speed_regs;
-#endif
typedef struct {
unsigned char btr0;
unsigned char btr1;
@@ -251,7 +253,9 @@ static CANMsg *occan_fifo_claim_get(occan_fifo *fifo);
static void occan_fifo_clr(occan_fifo *fifo);
/**** Hardware related Interface ****/
-static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result);
+static void convert_timing_to_btrs(
+ struct grlib_canbtrs_timing *t,
+ occan_speed_regs *btrs);
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing);
static void pelican_init(occan_priv *priv);
static void pelican_open(occan_priv *priv);
@@ -765,6 +769,7 @@ static void pelican_init(occan_priv *priv){
static void pelican_open(occan_priv *priv){
int ret;
+ struct grlib_canbtrs_timing timing;
/* Set defaults */
priv->speed = OCCAN_SPEED_250K;
@@ -783,13 +788,19 @@ static void pelican_open(occan_priv *priv){
*/
WRITE_REG(priv, &priv->regs->clkdiv, (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV));
- ret = occan_calc_speedregs(priv->sys_freq_hz,priv->speed,&priv->timing);
- if ( ret ){
+ ret = grlib_canbtrs_calc_timing(
+ priv->speed, priv->sys_freq_hz,
+ OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
+ (struct grlib_canbtrs_timing *)&timing);
+ if ( ret ) {
/* failed to set speed for this system freq, try with 50K instead */
priv->speed = OCCAN_SPEED_50K;
- occan_calc_speedregs(priv->sys_freq_hz, priv->speed,
- &priv->timing);
+ grlib_canbtrs_calc_timing(
+ priv->speed, priv->sys_freq_hz,
+ OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
+ (struct grlib_canbtrs_timing *)&timing);
}
+ convert_timing_to_btrs(&timing, &priv->timing);
/* disable all interrupts */
WRITE_REG(priv, &priv->regs->inten, 0);
@@ -983,97 +994,13 @@ static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned
WRITE_REG(priv, amask3, amask[3]);
}
-
-/* This function calculates BTR0 and BTR1 values for a given bitrate.
- *
- * Set communication parameters.
- * \param clock_hz OC_CAN Core frequency in Hz.
- * \param rate Requested baud rate in bits/second.
- * \param result Pointer to where resulting BTRs will be stored.
- * \return zero if successful to calculate a baud rate.
- */
-static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result)
+static void convert_timing_to_btrs(
+ struct grlib_canbtrs_timing *t,
+ occan_speed_regs *btrs)
{
- int best_error = 1000000000;
- int error;
- int best_tseg=0, best_brp=0, brp=0;
- int tseg=0, tseg1=0, tseg2=0;
- int sjw = 0;
- int clock = clock_hz / 2;
- int sampl_pt = 90;
-
- if ( (rate<5000) || (rate>1000000) ){
- /* invalid speed mode */
- return -1;
- }
-
- /* find best match, return -2 if no good reg
- * combination is available for this frequency */
-
- /* some heuristic specials */
- if (rate > ((1000000 + 500000) / 2))
- sampl_pt = 75;
-
- if (rate < ((12500 + 10000) / 2))
- sampl_pt = 75;
-
- if (rate < ((100000 + 125000) / 2))
- sjw = 1;
-
- /* tseg even = round down, odd = round up */
- for (tseg = (0 + 0 + 2) * 2;
- tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1;
- tseg++)
- {
- brp = clock / ((1 + tseg / 2) * rate) + tseg % 2;
- if ((brp == 0) || (brp > 64))
- continue;
-
- error = rate - clock / (brp * (1 + tseg / 2));
- if (error < 0)
- {
- error = -error;
- }
-
- if (error <= best_error)
- {
- best_error = error;
- best_tseg = tseg/2;
- best_brp = brp-1;
- }
- }
-
- if (best_error && (rate / best_error < 10))
- {
- printk("OCCAN: bitrate %d is not possible with %d Hz clock\n\r",rate, clock);
- return -2;
- }else if ( !result )
- return 0; /* nothing to store result in, but a valid bitrate can be calculated */
-
- tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
-
- if (tseg2 < 0)
- {
- tseg2 = 0;
- }
-
- if (tseg2 > MAX_TSEG2)
- {
- tseg2 = MAX_TSEG2;
- }
-
- tseg1 = best_tseg - tseg2 - 2;
-
- if (tseg1 > MAX_TSEG1)
- {
- tseg1 = MAX_TSEG1;
- tseg2 = best_tseg - tseg1 - 2;
- }
-
- result->btr0 = (sjw<<OCCAN_BUSTIM_SJW_BIT) | (best_brp&OCCAN_BUSTIM_BRP);
- result->btr1 = (0<<7) | (tseg2<<OCCAN_BUSTIM_TSEG2_BIT) | tseg1;
-
- return 0;
+ btrs->btr0 = (t->rsj << OCCAN_BUSTIM_SJW_BIT) |
+ (t->scaler & OCCAN_BUSTIM_BRP);
+ btrs->btr1 = (0<<7) | (t->ps2 << OCCAN_BUSTIM_TSEG2_BIT) | t->ps1;
}
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing)
@@ -1441,7 +1368,7 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
int ret;
- occan_speed_regs timing;
+ struct grlib_canbtrs_timing timing;
occan_priv *can;
struct drvmgr_dev *dev;
unsigned int speed;
@@ -1467,7 +1394,11 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
/* get speed rate from argument */
speed = (unsigned int)ioarg->buffer;
- ret = occan_calc_speedregs(can->sys_freq_hz,speed,&timing);
+ /* Calculate default timing register values */
+ ret = grlib_canbtrs_calc_timing(
+ speed, can->sys_freq_hz,
+ OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
+ (struct grlib_canbtrs_timing *)&timing);
if ( ret )
return RTEMS_INVALID_NAME; /* EINVAL */
@@ -1476,7 +1407,7 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
/* save timing/speed */
can->speed = speed;
- can->timing = timing;
+ convert_timing_to_btrs(&timing, &can->timing);
break;
case OCCAN_IOC_SET_BTRS:
--
2.7.4
More information about the devel
mailing list