[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