Ethernet - Transmitting and Receiving using Memory Copy

Reception using Memory Copy

On some devices, the MAC is not part of processor peripherals, and is connected through a serial or a parallel communication scheme. You will have to create specific data transfer functions for writing and reading the data structures of the MAC.

Processing reception buffers in the ISR

The following is a list of the actions that must be performed in NetDev_ISR_Handler() to receive packets using Memory Copy.

  • Read MAC Status Register
  • Handle Receive ISR:
  • Signal Net IF Receive task
  • Clear Interrupt
  • Handle any other reported interrupts by MAC controller.

The listing below shows a template for the NetDev_ISR_Handle() function:

Listing - ISR Handler function template
static  void  NetDev_ISR_Handler (NET_IF            *pif,
                                  NET_DEV_ISR_TYPE   type)
{
    NET_DEV_CFG_ETHER  *pdev_cfg;
    NET_DEV_DATA       *pdev_data;
    NET_DEV            *pdev;
    CPU_DATA            reg_val;
    CPU_INT08U         *p_data;
    NET_ERR             err;
   (void)&type;                                                             (1)
    pdev_cfg  = (NET_DEV_CFG_ETHER *)pif->Dev_Cfg;                          (2)
    pdev_data = (NET_DEV_DATA      *)pif->Dev_Data;                         (3)
    pdev      = (NET_DEV           *)pdev_cfg->BaseAddr;                    (4)
    reg_val = pdev->ISR;                                                    (5)
    if ((reg_val & RX_ISR_EVENT_MSK) > 0) {                                 (6)
         NetOS_IF_RxTaskSignal(pif->Nbr, &err);                             (7)
          switch (err) {
              case NET_IF_ERR_NONE:
                  No error during signalling.
                  break;
              case NET_IF_ERR_RX_Q_FULL:
              case NET_IF_ERR_RX_Q_SIGNAL_FAULT:
              default:
                  An error occurred during signalling.
                  break;
         }
         pdev->ISR |= RX_ISR_EVENT_MSK;                                     (8)
    }
                                                                            (9)
    if ((reg_val & TX_ISR_EVENT_MSK) > 0) {
                                                                            (10)
         p_data = (CPU_INT08U *)pdev_data->TxBufCompPtr;
         NetOS_IF_TxDeallocTaskPost(p_data, &err);
         NetOS_Dev_TxRdySignal(pif->Nbr);                                   (11)
         pdev->ISR |= TX_ISR_EVENT_MSK;                                     (12)
    }
    pdev->ISR |= UNHANDLED_ISR_EVENT_MASK;                                  (13)
}

(1) Prevent “variable unused” compiler warning.

(2) Obtain pointer to the device configuration structure.

(3) Obtain pointer to device data area.

(4) Overlay device register structure on top of device base address.

(5) Determine interrupt type.

(6) Handle reception interrupts.

(7) Signal NetIF reception queue task for each new ready descriptor.

(8) Clear device’s reception interrupt event flag.

(9) Handle transmission interrupts.

(10) Increment transmission packet counter.

(11) Signal NetIF that transmission resources are now available.

(12) Clear device’s transmission interrupt event flag.

(13) Clear unhandled interrupt event flag. 


Moving buffers from the device to the TCP-IP stack using Memory Copy

The following a list of the actions that must be performed in NetDev_Rx() to receive packets using Memory Copy.

  • Disable interrupts
  • Read the length of the received frame
  • Obtain pointer to new data area
  • Copy frame to new data area
  • Set return values. Pointer to received data area and size
  • Re-Enable interrupts
  • Check for additional ready frames, and signal Net IF receive task

The listing below shows a template for the NetDev_Rx() function:

Listing - NetDev_Rx() function template
static  void  NetDev_Rx (NET_IF       *pif,
                         CPU_INT08U  **p_data,
                         CPU_INT16U   *size,
                         NET_ERR      *perr)
{
    NET_DEV_CFG_ETHER  *pdev_cfg;
    NET_DEV_DATA       *pdev_data;
    NET_DEV            *pdev;
    CPU_INT08U         *pbuf_new;
    CPU_INT16S          length;
    CPU_INT16U          cnt;
    CPU_INT16U          i;
    pdev_cfg  = (NET_DEV_CFG_ETHER *)pif->Dev_Cfg;                                       (1)
    pdev_data = (NET_DEV_DATA      *)pif->Dev_Data;                                      (2)
    pdev      = (NET_DEV           *)pdev_cfg->BaseAddr;                                 (3)
                                            
    if ((pdev->RSTAT & RX_STATUS_ERR_MSK) > 0) {                                         (4)
        *size   = (CPU_INT16U  )0;
        *p_data = (CPU_INT08U *)0;
        *perr   = (NET_ERR     )NET_DEV_ERR_RX;
         return;
    }
                                            
    length = (pdev->STATUS & RX_STATUS_SIZE_MSK) - NET_IF_ETHER_FRAME_CRC_SIZE;         (5)
    if (length < NET_IF_ETHER_FRAME_MIN_SIZE) { 
       *size   = (CPU_INT16U  )0;
       *p_data = (CPU_INT08U *)0;
       *perr   = (NET_ERR     )NET_DEV_ERR_INVALID_SIZE;
        return;
    }
    pbuf_new = NetBuf_GetDataPtr((NET_IF        *)pif,                                  (6)
                                 (NET_TRANSACTION)NET_TRANSACTION_RX,
#if (NET_VERSION >= 21000u)
                                 (NET_BUF_SIZE   )NET_IF_ETHER_FRAME_MAX_SIZE,
                                 (NET_BUF_SIZE   )NET_IF_IX_RX,
                                 (NET_BUF_SIZE  *)0,
#else
                                 (NET_BUF_SIZE   )pdev_cfg->RxBufLargeSize,
                                 (NET_BUF_SIZE   )0u,
#endif
                                 (NET_BUF_SIZE  *)0,
                                 (NET_TYPE      *)0,
                                 (NET_ERR       *)perr);
    if (*perr != NET_BUF_ERR_NONE) {                                                    (7)
        *size   = (CPU_INT16U  )0;
        *p_data = (CPU_INT08U *)0;
         return;
    }
   *size   =  length;                                                                   (8)
    cnt    =  length / pdev_cfg->DataBusSizeNbrBits;                                    (9)
    for (i = 0; i < cnt; i++) {
        Read data from device using Memcopy.                                            (10)
    }
   *p_data = pbuf_new;                                                                  (11)
   *perr = NET_DEV_ERR_NONE;
}

(1) Obtain pointer to the device configuration structure.

(2) Obtain pointer to device data area.

(3) Overlay device register structure on top of device base address.

(4) If the frame contains reception errors, discard the frame by setting *size to 0, *p_data to null. Set *perr to NET_DEV_ERR_RX to indicate a reception error.

(5) If frame is a runt, discard the frame.

(6) Request an empty buffer.

(7) If unable to get a buffer, discard the frame.

(8) Return the size of the received frame.

(9) Determine the number of device memory or FIFO reads that are required to complete the memory copy.

(10) Read data from device.

(11) Return a pointer to the received data.

Transmission using Memory Copy

The following a list of the actions that must be done in NetDev_Tx() in order to implement transmission using Memory Copy:

  • Disable interrupts.
  • Prepare device to receive the transmit frame in memory.
  • Copy frame to transmit to MAC buffer.
  • If no frames are queued for transmission, issue a transmission request to the MAC.
  • Update the device’s list of transmit pointers
  • Re-enable interrupts

The listing below shows a template for the NetDev_Tx() function:

Listing - NetDev_Tx() function template
static  void  NetDev_Tx (NET_IF      *pif,
                         CPU_INT08U  *p_data,
                         CPU_INT16U   size,
                         NET_ERR     *perr)
{ 
    NET_DEV_CFG_ETHER  *pdev_cfg; 
    NET_DEV_DATA       *pdev_data; 
    NET_DEV            *pdev; 
    CPU_INT16U          cnt; 
    CPU_INT16U          i; 
    pdev_cfg  = (NET_DEV_CFG_ETHER *)pif->Dev_Cfg;                               (1)
    pdev_data = (NET_DEV_DATA      *)pif->Dev_Data;                              (2)
    pdev      = (NET_DEV           *)pdev_cfg->BaseAddr;                         (3)
    if ((pdev->STATUS & TX_STATUS_BUSY) > 0) {                                   (4)
      *perr = NET_DEV_ERR_TX_BUSY; 
       return; 
    }
    cnt = size / pdev_cfg->DataBusSizeNbrBits;                                   (5)
    for (i = 0; i < cnt; i++) {             
        Copy data to device using Memcopy                                        (6)
    }
    pdev->CTRL = 1;                                                              (7)
    pdev_data->TxBufCompPtr = p_data; 
}

The following is a list of actions that must be performed in NetDev_ISR_Handler() to transmit packets using Memory Copy.

(1) Obtain pointer to the device configuration structure.

(2) Obtain pointer to device data area.

(3) Overlay device register structure on top of the device base address.

(4) Check if the device is ready to transmit.

(5) Determine the number of device memory or FIFO writes that are required to complete the transfer.

(6) Copy data to device using memory copy.

(7) Initiate transmission of the packet.

Processing transmission buffer in the ISR

  • Setup next frame to transmit if any
  • Signal already transmitted frame for deallocation
  • Signal that Transmit resources have become available
  • Clear interrupt

For the template of NetDev_ISR_Handler() refer to the template in the listing above.