How to get latest Digi Embedded Linux FIM CAN Driver for Digi Connect ME 9210 and Connect Core 9P9215

Customers using Digi Connect ME 9210 with FIM CAN or ConnectCore 9P9215 with FIM CAN an Digi Embedded Linux DEL-5.7.2 having issues with timings not matching or wrong baudrate settings, as well as detection of bus-off does not work, should update to latest Linux driver 1.5 from 2017/February and current FIM firmware.

Either you update to latest DEL-5.7.3 with newer fim_can driver, or if you are staying with DEL-5.7.2 use patch below:

The FIM firmware fim_can.bin which is loaded during runtime by the driver into the FIM should be requested from Digi Technical Support through registration on:
https://www.digi.com/canbus

You should get the latest source code from with above request.
If you received your sources before 2017 you can patch fim_can.c to version 1.5 by applying patch:

--- fim_can_DEL57.c    2011-11-24 17:13:10.000000000 +0100
+++ fim_can.c    2017-03-13 12:58:27.000000000 +0100
@@ -9,7 +9,7 @@
  * under the terms of the GNU General Public License version 2 as published by
  * the Free Software Foundation.
  *
- *  !Revision:   $Revision: 1.2 $
+ *  !Revision:   $Revision: 1.5 $
  *  !Author:     Luis Galdos, Hector Oron
  *  !Descr:
  *  !References: Based on the virtual CAN driver (Copyright (c) 2002-2007
@@ -59,7 +59,7 @@
 #endif
 
 /* Driver informations */
-#define DRIVER_VERSION                "1.3"
+#define DRIVER_VERSION                "1.5"
 #define DRIVER_AUTHOR                "Luis Galdos, Hector Oron"
 #define DRIVER_DESC                "FIM CAN bus driver"
 #define FIM_DRIVER_NAME                "fim-can"
@@ -100,11 +100,12 @@
 #define FIM_CAN_NR_FILTERS            (8)
 
 /* Default timing values (see Net+OS driver: nacbus.c) */
-#define FIM_CAN_DEFAULT_SJW            (7)
-#define FIM_CAN_DEFAULT_PROPSEG            (8)
-#define FIM_CAN_DEFAULT_PHASE1            (8)
-#define FIM_CAN_DEFAULT_PHASE2            (8)
+#define FIM_CAN_DEFAULT_SJW            (1)
+#define FIM_CAN_DEFAULT_PROPSEG            (0)
+#define FIM_CAN_DEFAULT_PHASE1            (1)
+#define FIM_CAN_DEFAULT_PHASE2            (1)
 #define FIM_CAN_DEFAULT_BITRATE            500000
+#define FIM_CAN_DEFAULT_SAMPLE_POINT    875
 
 /* Maximal values from the Net+OS driver */
 #define FIM_CAN_MAX_BITRATE                    (1000000)
@@ -364,8 +365,8 @@
      * In the future we will probably need different latency times for the
      * bitrates. Let us keep this function for this purpose.
      */
-#define FIM_CAN_RXIRQ_LATENCY        (1)
-#define FIM_CAN_TXIRQ_LATENCY        (100)
+#define FIM_CAN_RXIRQ_LATENCY        (24)
+#define FIM_CAN_TXIRQ_LATENCY        (22)
     *rx = FIM_CAN_RXIRQ_LATENCY;
     *tx = FIM_CAN_TXIRQ_LATENCY;
     ret = 0;
@@ -396,12 +397,11 @@
     struct can_bittiming *bt;
 
     bt = &port->can.bittiming;
-    printk_debug("New timing: %u bps | sjw %u | sample %u | sync %u | clock %u\n",
+    printk_debug("New timing: %u bps | sjw %u | sample %u | sync %u\n",
              bt->bitrate,
              sjw,
              sample_point,
-             sync_period,
-             bt->clock);
+             sync_period);
 
     if (fim_can_calculate_latency(bt->bitrate, &larx, &latx)) {
         printk_err("Failed latency calculation for rate %u\n", bt->bitrate);
@@ -450,6 +450,7 @@
     unsigned char *ptr;
     unsigned char data[sizeof(struct fim_can_timing_t) + (FIM_CAN_NR_FILTERS * 8)];
     struct can_bittiming *bt;
+    unsigned int total_tq = 0, round_up_tq = 0;
 
     /* Init the timing parameters */
     memset(&cfg, 0, sizeof(cfg));
@@ -461,22 +462,28 @@
         return -EINVAL;
     }
 
-    /* We must use the default bit rates for our FIM-firmware */
-    if (!bt->sjw)
+    /*
+     * Use our defaults if user has not supplied timing values.
+     */
+    if ((bt->sjw == 0) || (bt->tq == 0) || (bt->sample_point == 0)) {
         bt->sjw = FIM_CAN_DEFAULT_SJW;
-    if (!bt->prop_seg)
         bt->prop_seg = FIM_CAN_DEFAULT_PROPSEG;
-
-    if (!bt->phase_seg1)
         bt->phase_seg1 = FIM_CAN_DEFAULT_PHASE1;
-
-    if (!bt->phase_seg2)
         bt->phase_seg2 = FIM_CAN_DEFAULT_PHASE2;
+        bt->sample_point = FIM_CAN_DEFAULT_SAMPLE_POINT;
+    }
 
+    total_tq = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1; /* +1 to include sync segment*/
+    round_up_tq = total_tq / 2;
+
+    /*
+     * fim_can_fill_timing wants values expressed as percentages of the total bit time, so
+     * make the necessary adjustments to the parameters that we pass to it.
+     */
     fim_can_fill_timing(port, &cfg,
-                bt->sjw,
-                bt->prop_seg + bt->phase_seg1 + 1,
-                bt->phase_seg2);
+                ((100 * bt->sjw) + round_up_tq) / total_tq,
+                (bt->sample_point + 5)/10,
+                (100 + round_up_tq) / total_tq);        /* timing for sync segment*/
 
     fim_can_do_dump_timing(&cfg,
                    bt->sjw,
@@ -739,7 +746,12 @@
     }
     retval = fim_can_restart_fim(port);
     if (!retval) {
-        netif_start_queue(dev);
+        if (dev->operstate == IF_OPER_DOWN) {
+            netif_carrier_on(dev);
+            netif_wake_queue(dev);
+        } else {
+            netif_start_queue(dev);
+        }
         port->can.state = CAN_STATE_ERROR_ACTIVE;
         port->opened = 1;
     }
@@ -920,11 +932,13 @@
     struct can_frame *cf;
     unsigned int bus, fatal;
     struct net_device_stats *stats = &dev->stats;
+    enum can_state state;
 
     port = netdev_priv(dev);
     fim = &port->fim;
     fim_get_exp_reg(fim, FIM_CAN_BUSSTATE_REG, &bus);
     fim_get_exp_reg(fim, FIM_CAN_FATALERR_REG, &fatal);
+    state = port->can.state;
 
     if ((!bus) && (!fatal) && (!is_transmit_failure))
         return 0;
@@ -958,8 +972,10 @@
      * The corresponding error flags are under: include/linux/can/error.h
      */
     if (bus & FIM_CAN_BUSSTATE_OFF) {
+        state = CAN_STATE_BUS_OFF;
         cf->can_id |= CAN_ERR_BUSOFF;
-        can_bus_off(dev);
+        netif_carrier_off(dev);
+        port->can.can_stats.bus_off++;
         }
 
     /* @XXX: This seems to be the correct flags for our controller, or? */
@@ -971,8 +987,11 @@
 
         if (is_transmit_failure) {
             cf->can_id |= CAN_ERR_ACK;
+        stats->tx_errors++;
         }
 
+        port->can.state = state;
+
     /* Pass the error frame to the socket layer */
     netif_rx(skb);
 
@@ -1252,6 +1271,7 @@
     skb = dev_alloc_skb(sizeof(struct can_frame));
     if (!skb) {
         printk_err("No memory available? Dropping a CAN-frame!\n");
+        stats->rx_errors++;
         goto fim_can_rx_isr_exit;
     }

Last updated: Sep 27, 2024

Filed Under

Embedded

Recently Viewed

No recently viewed articles

Did you find this article helpful?