You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/03/18 13:35:19 UTC

[incubator-nuttx] 02/23: FlexCAN transmit CAN FD support

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch SocketCAN
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 09886c8b92b7e65a2ff381caafe86b16fecd564e
Author: Peter van der Perk <pe...@nxp.com>
AuthorDate: Tue Feb 25 16:56:26 2020 +0100

    FlexCAN transmit CAN FD support
    
    Also checks now if TX MB is full so that transmit blocks
    Note receive performance is affect by non-optimized memcpy please use ARMV7M_MEMCPY for best performance
    Removed unused g_desc_pool
---
 arch/arm/src/s32k1xx/s32k1xx_flexcan.c | 279 ++++++++++++++++++++-------------
 net/can/can_callback.c                 |   1 +
 2 files changed, 172 insertions(+), 108 deletions(-)

diff --git a/arch/arm/src/s32k1xx/s32k1xx_flexcan.c b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
index bb0d1d0..f394a20 100644
--- a/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
+++ b/arch/arm/src/s32k1xx/s32k1xx_flexcan.c
@@ -114,6 +114,8 @@
 #define CAN_FIFO_OV                 (1 << 6)
 #define CAN_FIFO_WARN               (1 << 7)
 
+#define POOL_SIZE                   1
+
 /* Interrupt flags for RX fifo */
 #define IFLAG1_RXFIFO               (CAN_FIFO_NE | CAN_FIFO_WARN | CAN_FIFO_OV)
 
@@ -236,8 +238,13 @@ struct s32k1xx_driver_s
   WDOG_ID txtimeout;           /* TX timeout timer */
   struct work_s irqwork;       /* For deferring interrupt work to the work queue */
   struct work_s pollwork;      /* For deferring poll work to the work queue */
-  struct enet_desc_s *txdesc;  /* A pointer to the list of TX descriptor */
-  struct enet_desc_s *rxdesc;  /* A pointer to the list of RX descriptors */
+#ifdef CAN_FD
+  struct canfd_frame *txdesc;  /* A pointer to the list of TX descriptor */
+  struct canfd_frame *rxdesc;  /* A pointer to the list of RX descriptors */
+#else
+  struct can_frame *txdesc;  /* A pointer to the list of TX descriptor */
+  struct can_frame *rxdesc;  /* A pointer to the list of RX descriptors */
+#endif
 
   /* This holds the information visible to the NuttX network */
 
@@ -253,8 +260,16 @@ struct s32k1xx_driver_s
 
 static struct s32k1xx_driver_s g_flexcan[CONFIG_S32K1XX_ENET_NETHIFS];
 
-static uint8_t g_desc_pool[2000]
+#ifdef CAN_FD
+static uint8_t g_tx_pool[sizeof(struct canfd_frame)*POOL_SIZE];
+static uint8_t g_rx_pool[sizeof(struct canfd_frame)*POOL_SIZE];
+#else
+static uint8_t g_tx_pool[sizeof(struct can_frame)*POOL_SIZE]
+               __attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+static uint8_t g_rx_pool[sizeof(struct can_frame)*POOL_SIZE]
                __attribute__((aligned(ARMV7M_DCACHE_LINESIZE)));
+#endif
+
 
 /****************************************************************************
  * Private Function Prototypes
@@ -368,16 +383,17 @@ static void s32k1xx_reset(struct s32k1xx_driver_s *priv);
 
 static bool s32k1xx_txringfull(FAR struct s32k1xx_driver_s *priv)
 {
-  uint8_t txnext;
-
-  /* Check if there is room in the hardware to hold another outgoing
-   * packet.  The ring is full if incrementing the head pointer would
-   * collide with the tail pointer.
-   */
-
-  txnext = priv->txhead + 1;
+  uint32_t mbi = 0;
 
-  return priv->txtail == txnext;
+  while (mbi < TXMBCOUNT)
+	{
+	  if (priv->tx[mbi].cs.code != CAN_TXMB_DATAORREMOTE)
+		{
+		  return 0;
+		}
+	  mbi++;
+	}
+  return 1;
 }
 
 /****************************************************************************
@@ -404,19 +420,6 @@ static int s32k1xx_transmit(FAR struct s32k1xx_driver_s *priv)
 {
   #warning Missing logic
 
-  struct can_frame *frame = (struct can_frame *)priv->dev.d_buf;
-
-#if 0
-  ninfo("CAN id: %i dlc: %i", frame->can_id, frame->can_dlc);
-
-  for (int i = 0; i < frame->can_dlc; i++)
-    {
-      ninfo(" %02X", frame->data[i]);
-    }
-
-  ninfo("\r\n");
-#endif
-
   /* Attempt to write frame */
 
   uint32_t mbi = 0;
@@ -456,45 +459,98 @@ static int s32k1xx_transmit(FAR struct s32k1xx_driver_s *priv)
   struct mb_s *mb = &priv->tx[mbi];
   mb->cs.code = CAN_TXMB_INACTIVE;
 
-  if (0) /* FIXME detect Std or Ext id */
-    {
-      cs.ide = 1;
-      mb->id.ext = frame->can_id & MASKEXTID;
-    }
-  else
+  if(priv->dev.d_len == sizeof(struct can_frame))
     {
-      mb->id.std = frame->can_id & MASKSTDID;
-    }
+	  struct can_frame *frame = (struct can_frame *)priv->dev.d_buf;
 
-#if 0
-  cs.rtr = frame.isRemoteTransmissionRequest();
-#endif
+	  if (0) /* FIXME detect Std or Ext id */
+	    {
+	      cs.ide = 1;
+	      mb->id.ext = frame->can_id & MASKEXTID;
+	    }
+	  else
+	    {
+	      mb->id.std = frame->can_id & MASKSTDID;
+	    }
 
-  cs.dlc = frame->can_dlc;
+	#if 0
+	  cs.rtr = frame.isRemoteTransmissionRequest();
+	#endif
 
-  /* FIXME endian swap instruction or somekind takes 1.5us right now */
+	  cs.dlc = frame->can_dlc;
 
-  mb->data[0].b00 = frame->data[0];
-  mb->data[0].b01 = frame->data[1];
-  mb->data[0].b02 = frame->data[2];
-  mb->data[0].b03 = frame->data[3];
-  mb->data[1].b00 = frame->data[4];
-  mb->data[1].b01 = frame->data[5];
-  mb->data[1].b02 = frame->data[6];
-  mb->data[1].b03 = frame->data[7];
+	  mb->data[0].w00 = __builtin_bswap32(*(uint32_t*)&frame->data[0]);
+	  mb->data[1].w00 = __builtin_bswap32(*(uint32_t*)&frame->data[4]);
 
-#if 0
-  /* Registering the pending transmission so we can track its deadline and
-   * loopback it as needed
-   */
+    }
+  else /* CAN FD frame */
+    {
+  	  struct canfd_frame *frame = (struct canfd_frame *)priv->dev.d_buf;
+
+  	  cs.edl = 1; /* CAN FD Frame */
+
+  	  if (0) /* FIXME detect Std or Ext id */
+  	    {
+  	      cs.ide = 1;
+  	      mb->id.ext = frame->can_id & MASKEXTID;
+  	    }
+  	  else
+  	    {
+  	      mb->id.std = frame->can_id & MASKSTDID;
+  	    }
+
+  	#if 0
+  	  cs.rtr = frame.isRemoteTransmissionRequest();
+  	#endif
+
+  	  if(frame->len < 9)
+  	    {
+  		  cs.dlc = frame->len;
+  	    }
+  	  else
+  	    {
+  	      if (frame->len < 13)
+  	        {
+			  cs.dlc = 9;
+  	        }
+  	      else if (frame->len < 17)
+  	        {
+			   cs.dlc = 10;
+  	        }
+  	      else if (frame->len < 21)
+  	        {
+			   cs.dlc = 11;
+  	        }
+  	      else if (frame->len < 25)
+  	        {
+			   cs.dlc = 12;
+  	        }
+  	      else if (frame->len < 33)
+  	        {
+			   cs.dlc = 13;
+  	        }
+  	      else if (frame->len < 49)
+  	        {
+			   cs.dlc = 14;
+  	        }
+  	      else if (frame->len < 65)
+  	        {
+			   cs.dlc = 15;
+  	        }
+  	      else
+  	        {
+  	    	   cs.dlc = 15; /* FIXME check CAN FD spec */
+  	        }
+  	    }
+
+  	  uint32_t* frame_data_word = (uint32_t*)&frame->data[0];
+
+	  for(int i = 0; i < (frame->len + 4 - 1) / 4; i++)
+		{
+	  	  mb->data[i].w00 = __builtin_bswap32(frame_data_word[i]);
+		}
+    }
 
-  txitem& txi        = pending_tx_[mbi];
-  txi.deadline       = tx_deadline;
-  txi.frame          = frame;
-  txi.loopback       = (flags & uavcan::CanIOFlagLoopback) != 0;
-  txi.abort_on_error = (flags & uavcan::CanIOFlagAbortOnError) != 0;
-  txi.pending        = txitem::busy;
-#endif
 
   s32k1xx_gpiowrite(PIN_PORTD | PIN31, 0);
 
@@ -552,6 +608,7 @@ static int s32k1xx_txpoll(struct net_driver_s *dev)
 
           s32k1xx_transmit(priv);
 #if 0
+          //FIXME implement ring buffer and increment pointer just like the enet driver??
           priv->dev.d_buf =
             (uint8_t *)s32k1xx_swap32((uint32_t)priv->txdesc[priv->txhead].data);
 #endif
@@ -633,138 +690,127 @@ static void s32k1xx_receive(FAR struct s32k1xx_driver_s *priv, uint32_t flags)
 
       if(rf->cs.edl) /* CAN FD frame */
         {
-
-    	  struct canfd_frame frame;
+    	  struct canfd_frame* frame = priv->rxdesc;
 
           if (rf->cs.ide)
             {
-              frame.can_id = MASKEXTID & rf->id.ext;
-              frame.can_id |= FLAGEFF;
+              frame->can_id = MASKEXTID & rf->id.ext;
+              frame->can_id |= FLAGEFF;
             }
           else
             {
-              frame.can_id = MASKSTDID & rf->id.std;
+              frame->can_id = MASKSTDID & rf->id.std;
             }
 
           if (rf->cs.rtr)
             {
-              frame.can_id |= FLAGRTR;
+              frame->can_id |= FLAGRTR;
             }
 
           if(rf->cs.dlc < 9){
-              frame.len = rf->cs.dlc;
+              frame->len = rf->cs.dlc;
           } else {
         	  switch(rf->cs.dlc)
         	    {
         	     case 9:
-        	       frame.len = 12;
+        	       frame->len = 12;
         	       break;
 
         	     case 10:
-        	       frame.len = 16;
+        	       frame->len = 16;
         	       break;
 
         	     case 11:
-        	       frame.len = 20;
+        	       frame->len = 20;
         	       break;
 
         	     case 12:
-        	       frame.len = 24;
+        	       frame->len = 24;
         	       break;
 
         	     case 13:
-        	       frame.len = 32;
+        	       frame->len = 32;
         	       break;
 
         	     case 14:
-        	       frame.len = 48;
+        	       frame->len = 48;
         	       break;
 
         	     case 15:
-        	       frame.len = 64;
+        	       frame->len = 64;
         	       break;
         	    }
           }
 
-    	  int j = 0;
-          for(int i = 0; i < (frame.len + 4 - 1) / 4; i++)
+    	  uint32_t* frame_data_word = (uint32_t*)&frame->data[0];
+
+          for(int i = 0; i < (frame->len + 4 - 1) / 4; i++)
             {
-              frame.data[0+j] = rf->data[i].b00;
-              frame.data[1+j] = rf->data[i].b01;
-              frame.data[2+j] = rf->data[i].b02;
-              frame.data[3+j] = rf->data[i].b03;
-              j = j + 4;
+        	  frame_data_word[i] = __builtin_bswap32(rf->data[i].w00);
             }
 
           /* Clear MB interrupt flag */
           regval  = getreg32(S32K1XX_CAN0_IFLAG1);
-          regval |= (1 << mb_index);
+          regval |= (0x80000000 >> mb_index);
           putreg32(regval, S32K1XX_CAN0_IFLAG1);
 
-          /* Copy the buffer pointer to priv->dev.d_buf.  Set amount of data
+          /* Copy the buffer pointer to priv->dev..  Set amount of data
            * in priv->dev.d_len
            */
 
           priv->dev.d_len = sizeof(struct canfd_frame);
-          priv->dev.d_buf = (uint8_t *)s32k1xx_swap32((uint32_t)&frame); /* FIXME */
+          priv->dev.d_buf = frame;
         }
       else /* CAN 2.0 Frame */
         {
-    	  struct can_frame frame;
+    	  struct can_frame* frame = priv->rxdesc;
 
           if (rf->cs.ide)
             {
-              frame.can_id = MASKEXTID & rf->id.ext;
-              frame.can_id |= FLAGEFF;
+              frame->can_id = MASKEXTID & rf->id.ext;
+              frame->can_id |= FLAGEFF;
             }
           else
             {
-              frame.can_id = MASKSTDID & rf->id.std;
+              frame->can_id = MASKSTDID & rf->id.std;
             }
 
           if (rf->cs.rtr)
             {
-              frame.can_id |= FLAGRTR;
+              frame->can_id |= FLAGRTR;
             }
 
-          frame.can_dlc = rf->cs.dlc;
+          frame->can_dlc = rf->cs.dlc;
 
-          frame.data[0] = rf->data[0].b00;
-          frame.data[1] = rf->data[0].b01;
-          frame.data[2] = rf->data[0].b02;
-          frame.data[3] = rf->data[0].b03;
-          frame.data[4] = rf->data[1].b00;
-          frame.data[5] = rf->data[1].b01;
-          frame.data[6] = rf->data[1].b02;
-          frame.data[7] = rf->data[1].b03;
+    	  *(uint32_t*)&frame->data[0] = __builtin_bswap32(rf->data[0].w00);
+    	  *(uint32_t*)&frame->data[4] = __builtin_bswap32(rf->data[1].w00);
 
           /* Clear MB interrupt flag */
           regval  = getreg32(S32K1XX_CAN0_IFLAG1);
           regval |= (1 << mb_index);
           putreg32(regval, S32K1XX_CAN0_IFLAG1);
 
-          /* Copy the buffer pointer to priv->dev.d_buf.  Set amount of data
+          /* Copy the buffer pointer to priv->dev..  Set amount of data
            * in priv->dev.d_len
            */
 
           priv->dev.d_len = sizeof(struct can_frame);
-          priv->dev.d_buf = (uint8_t *)s32k1xx_swap32((uint32_t)&frame); /* FIXME */
+          priv->dev.d_buf = frame;
         }
 
-      /* Invalidate the buffer so that the correct packet will be re-read
-       * from memory when the packet content is accessed.
-       */
-
-      up_invalidate_dcache((uintptr_t)priv->dev.d_buf,
-                      (uintptr_t)priv->dev.d_buf + priv->dev.d_len);
-
       /* Send to socket interface */
 
       NETDEV_RXPACKETS(&priv->dev);
 
       can_input(&priv->dev);
 
-      /* Store with timeout into the FIFO buffer and signal update event */
+      /* Point the packet buffer back to the next Tx buffer that will be
+       * used during the next write.  If the write queue is full, then
+       * this will point at an active buffer, which must not be written
+       * to.  This is OK because devif_poll won't be called unless the
+       * queue is not full.
+       */
+      priv->dev.d_buf = priv->txdesc;
     }
 }
 
@@ -790,6 +836,12 @@ static void s32k1xx_txdone(FAR struct s32k1xx_driver_s *priv, uint32_t flags)
 {
   #warning Missing logic
 
+  /* We are here because a transmission completed, so the watchdog can be
+   * canceled.
+   */
+
+  wd_cancel(priv->txtimeout);
+
   /* FIXME process aborts */
 
   /* Process TX completions */
@@ -805,10 +857,18 @@ static void s32k1xx_txdone(FAR struct s32k1xx_driver_s *priv, uint32_t flags)
           const bool txok = priv->tx[mbi].cs.code != CAN_TXMB_ABORT;
           handleTxMailboxInterrupt(mbi, txok, utc_usec);
 #endif
+
+          NETDEV_TXDONE(&priv->dev);
         }
 
       mb_bit <<= 1;
     }
+
+  /* There should be space for a new TX in any event.  Poll the network for
+   * new XMIT data
+   */
+
+  devif_poll(&priv->dev, s32k1xx_txpoll);
 }
 
 /****************************************************************************
@@ -950,7 +1010,7 @@ static void s32k1xx_poll_work(FAR void *arg)
    */
 
   net_lock();
-  if (1) /* !s32k1xx_txringfull(priv)) */
+  if (!s32k1xx_txringfull(priv))
     {
       /* If so, update TCP timing states and poll the network for new XMIT
        * data. Hmmm.. might be bug here.  Does this mean if there is a
@@ -1096,7 +1156,10 @@ static int s32k1xx_ifup(struct net_driver_s *dev)
 
   priv->bifup = true;
 
-  priv->dev.d_buf = &g_desc_pool;
+  priv->txdesc = &g_tx_pool;
+  priv->rxdesc = &g_rx_pool;
+
+  priv->dev.d_buf = priv->txdesc;
 
   /* Set interrupts */
 
@@ -1461,7 +1524,7 @@ static void s32k1xx_reset(struct s32k1xx_driver_s *priv)
             (((TOTALMBCOUNT - 1) << CAN_MCR_MAXMB_SHIFT) & CAN_MCR_MAXMB_MASK);
   putreg32(regval, S32K1XX_CAN0_MCR);
 
-  regval  = CAN_CTRL2_RRS | CAN_CTRL2_EACEN | CAN_CTRL2_RFFN_16MB; /* FIXME TASD */
+  regval  = CAN_CTRL2_RRS | CAN_CTRL2_EACEN; /* FIXME TASD */
   putreg32(regval, S32K1XX_CAN0_CTRL2);
 
   for (i = 0; i < TOTALMBCOUNT; i++)
diff --git a/net/can/can_callback.c b/net/can/can_callback.c
index c61bdce..0f60b6a 100644
--- a/net/can/can_callback.c
+++ b/net/can/can_callback.c
@@ -30,6 +30,7 @@
 
 #include <nuttx/net/netconfig.h>
 #include <nuttx/net/netdev.h>
+#include <nuttx/mm/iob.h>
 
 #include "devif/devif.h"
 #include "can/can.h"