w5500驱动_w5500和w5100s驱动程序 - CSDN
  • /* ...  * ALL RIGHT RESERVED ... * FileName : w5500.c  * -----------------------------------------------------------------  */ #include #include #include "w5500/config.h" #inc

    /*
     * (c)COPYRIGHT
     * ALL RIGHT RESERVED
     *
     * FileName : w5500.c
      * -----------------------------------------------------------------
     */
    #include <stdio.h>
    #include <string.h>
    #include "w5500/config.h"
    #include "w5500/SPI2.h"
    #include "w5500/w5500.h"
    #include "w5500/socket.h"
    #ifdef __DEF_IINCHIP_PPP__
       #include "md5.h"
    #endif

    static uint8 I_STATUS[MAX_SOCK_NUM];
    static uint16 SSIZE[MAX_SOCK_NUM]; /**< Max Tx buffer size by each channel */
    static uint16 RSIZE[MAX_SOCK_NUM]; /**< Max Rx buffer size by each channel */

    uint8 getISR(uint8 s)
    {
      return I_STATUS[s];
    }
    void putISR(uint8 s, uint8 val)
    {
       I_STATUS[s] = val;
    }

    uint16 getIINCHIP_RxMAX(uint8 s)
    {
       return RSIZE[s];
    }
    uint16 getIINCHIP_TxMAX(uint8 s)
    {
       return SSIZE[s];
    }
    void IINCHIP_CSoff(void)
    {
      WIZ_CS(LOW);
    }
    void IINCHIP_CSon(void)
    {
       WIZ_CS(HIGH);
    }
    uint8  IINCHIP_SpiSendData(uint8 dat)
    {
       return(SPI2_SendByte(dat));
    }

    void IINCHIP_WRITE( uint32 addrbsb,  uint8 data)
    {
       IINCHIP_ISR_DISABLE();                        // Interrupt Service Routine Disable
       IINCHIP_CSoff();                              // CS=0, SPI start
       IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
       IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
       IINCHIP_SpiSendData( (addrbsb & 0x000000F8) + 4);    // Data write command and Write data length 1
       IINCHIP_SpiSendData(data);                    // Data write (write 1byte data)
       IINCHIP_CSon();                               // CS=1,  SPI end
       IINCHIP_ISR_ENABLE();                         // Interrupt Service Routine Enable
    }

    uint8 IINCHIP_READ(uint32 addrbsb)
    {
       uint8 data = 0;
       IINCHIP_ISR_DISABLE();                        // Interrupt Service Routine Disable
       IINCHIP_CSoff();                              // CS=0, SPI start
       IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
       IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
       IINCHIP_SpiSendData( (addrbsb & 0x000000F8))    ;// Data read command and Read data length 1
       data = IINCHIP_SpiSendData(0x00);             // Data read (read 1byte data)
       IINCHIP_CSon();                               // CS=1,  SPI end
       IINCHIP_ISR_ENABLE();                         // Interrupt Service Routine Enable
       return data;   
    }

    uint16 wiz_write_buf(uint32 addrbsb,uint8* buf,uint16 len)
    {
       uint16 idx = 0;
       if(len == 0) ;//printf("Unexpected2 length 0\r\n");

       IINCHIP_ISR_DISABLE();
       IINCHIP_CSoff();                              // CS=0, SPI start
       IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
       IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
       IINCHIP_SpiSendData( (addrbsb & 0x000000F8) + 4);    // Data write command and Write data length 1
       for(idx = 0; idx < len; idx++)                // Write data in loop
       {
         IINCHIP_SpiSendData(buf[idx]);
       }
       IINCHIP_CSon();                               // CS=1, SPI end
       IINCHIP_ISR_ENABLE();                         // Interrupt Service Routine Enable   

       return len; 
    }

    uint16 wiz_read_buf(uint32 addrbsb, uint8* buf,uint16 len)
    {
      uint16 idx = 0;
      if(len == 0)
      {
        //printf("Unexpected2 length 0\r\n");
      }

      IINCHIP_ISR_DISABLE();
      //SPI MODE I/F
      IINCHIP_CSoff();                                  // CS=0, SPI start
      IINCHIP_SpiSendData( (addrbsb & 0x00FF0000)>>16);// Address byte 1
      IINCHIP_SpiSendData( (addrbsb & 0x0000FF00)>> 8);// Address byte 2
      IINCHIP_SpiSendData( (addrbsb & 0x000000F8));    // Data write command and Write data length 1
      for(idx = 0; idx < len; idx++)                    // Write data in loop
      {
        buf[idx] = IINCHIP_SpiSendData(0x00);
      }
      IINCHIP_CSon();                                   // CS=1, SPI end
      IINCHIP_ISR_ENABLE();                             // Interrupt Service Routine Enable
     
      return len;
    }


    /**
    @brief  This function is for resetting of the iinchip. Initializes the iinchip to work in whether DIRECT or INDIRECT mode
    */
    void iinchip_init(void)
    {
      setMR( MR_RST );
    #ifdef __DEF_IINCHIP_DBG__
      printf("MR value is %02x \r\n",IINCHIP_READ_COMMON(MR));
    #endif
    }

    /**
    @brief  This function set the transmit & receive buffer size as per the channels is used
    Note for TMSR and RMSR bits are as follows\n
    bit 1-0 : memory size of channel #0 \n
    bit 3-2 : memory size of channel #1 \n
    bit 5-4 : memory size of channel #2 \n
    bit 7-6 : memory size of channel #3 \n
    bit 9-8 : memory size of channel #4 \n
    bit 11-10 : memory size of channel #5 \n
    bit 12-12 : memory size of channel #6 \n
    bit 15-14 : memory size of channel #7 \n
    Maximum memory size for Tx, Rx in the W5500 is 16K Bytes,\n
    In the range of 16KBytes, the memory size could be allocated dynamically by each channel.\n
    Be attentive to sum of memory size shouldn't exceed 8Kbytes\n
    and to data transmission and receiption from non-allocated channel may cause some problems.\n
    If the 16KBytes memory is already  assigned to centain channel, \n
    other 3 channels couldn't be used, for there's no available memory.\n
    If two 4KBytes memory are assigned to two each channels, \n
    other 2 channels couldn't be used, for there's no available memory.\n
    */
    void sysinit( uint8 * tx_size, uint8 * rx_size  )
    {
      int16 i;
      int16 ssum,rsum;
    #ifdef __DEF_IINCHIP_DBG__
      printf("sysinit()\r\n");
    #endif
      ssum = 0;
      rsum = 0;

      for (i = 0 ; i < MAX_SOCK_NUM; i++)       // Set the size, masking and base address of Tx & Rx memory by each channel
      {
              IINCHIP_WRITE( (Sn_TXMEM_SIZE(i)), tx_size[i]);
              IINCHIP_WRITE( (Sn_RXMEM_SIZE(i)), rx_size[i]);
             
    #ifdef __DEF_IINCHIP_DBG__
             printf("tx_size[%d]: %d, Sn_TXMEM_SIZE = %d\r\n",i, tx_size[i], IINCHIP_READ(Sn_TXMEM_SIZE(i)));
             printf("rx_size[%d]: %d, Sn_RXMEM_SIZE = %d\r\n",i, rx_size[i], IINCHIP_READ(Sn_RXMEM_SIZE(i)));
    #endif
        SSIZE[i] = (int16)(0);
        RSIZE[i] = (int16)(0);


        if (ssum <= 16384)
        {
             switch( tx_size[i] )
          {
          case 1:
            SSIZE[i] = (int16)(1024);
            break;
          case 2:
            SSIZE[i] = (int16)(2048);
            break;
          case 4:
            SSIZE[i] = (int16)(4096);
            break;
          case 8:
            SSIZE[i] = (int16)(8192);
            break;
          case 16:
            SSIZE[i] = (int16)(16384);
          break;
          default :
            RSIZE[i] = (int16)(2048);
            break;
          }
        }

       if (rsum <= 16384)
        {
             switch( rx_size[i] )
          {
          case 1:
            RSIZE[i] = (int16)(1024);
            break;
          case 2:
            RSIZE[i] = (int16)(2048);
            break;
          case 4:
            RSIZE[i] = (int16)(4096);
            break;
          case 8:
            RSIZE[i] = (int16)(8192);
            break;
          case 16:
            RSIZE[i] = (int16)(16384);
            break;
          default :
            RSIZE[i] = (int16)(2048);
            break;
          }
        }
        ssum += SSIZE[i];
        rsum += RSIZE[i];

      }
    }

    // added

    /**
    @brief  This function sets up gateway IP address.
    */
    void setGAR(
      uint8 * addr  /**< a pointer to a 4 -byte array responsible to set the Gateway IP address. */
      )
    {
        wiz_write_buf(GAR0, addr, 4);
    }
    void getGWIP(uint8 * addr)
    {
        wiz_read_buf(GAR0, addr, 4);
    }

    /**
    @brief  It sets up SubnetMask address
    */
    void setSUBR(uint8 * addr)
    {  
        wiz_write_buf(SUBR0, addr, 4);
    }
    /**
    @brief  This function sets up MAC address.
    */
    void setSHAR(
      uint8 * addr  /**< a pointer to a 6 -byte array responsible to set the MAC address. */
      )
    {
      wiz_write_buf(SHAR0, addr, 6); 
    }

    /**
    @brief  This function sets up Source IP address.
    */
    void setSIPR(
      uint8 * addr  /**< a pointer to a 4 -byte array responsible to set the Source IP address. */
      )
    {
        wiz_write_buf(SIPR0, addr, 4); 
    }

    /**
    @brief  This function sets up Source IP address.
    */
    void getGAR(uint8 * addr)
    {
        wiz_read_buf(GAR0, addr, 4);
    }
    void getSUBR(uint8 * addr)
    {
        wiz_read_buf(SUBR0, addr, 4);
    }
    void getSHAR(uint8 * addr)
    {
        wiz_read_buf(SHAR0, addr, 6);
    }
    void getSIPR(uint8 * addr)
    {
        wiz_read_buf(SIPR0, addr, 4);
    }

    void setMR(uint8 val)
    {
      IINCHIP_WRITE(MR,val);
    }

    /**
    @brief  This function gets Interrupt register in common register.
     */
    uint8 getIR( void )
    {
       return IINCHIP_READ(IR);
    }

    /**
    @brief  This function sets up Retransmission time.

    If there is no response from the peer or delay in response then retransmission
    will be there as per RTR (Retry Time-value Register)setting
    */
    void setRTR(uint16 timeout)
    {
      IINCHIP_WRITE(RTR0,(uint8)((timeout & 0xff00) >> 8));
      IINCHIP_WRITE(RTR1,(uint8)(timeout & 0x00ff));
    }

    /**
    @brief  This function set the number of Retransmission.

    If there is no response from the peer or delay in response then recorded time
    as per RTR & RCR register seeting then time out will occur.
    */
    void setRCR(uint8 retry)
    {
      IINCHIP_WRITE(WIZ_RCR,retry);
    }

    /**
    @brief  This function set the interrupt mask Enable/Disable appropriate Interrupt. ('1' : interrupt enable)

    If any bit in IMR is set as '0' then there is not interrupt signal though the bit is
    set in IR register.
    */
    void clearIR(uint8 mask)
    {
      IINCHIP_WRITE(IR, ~mask | getIR() ); // must be setted 0x10.
    }

    /**
    @brief  This sets the maximum segment size of TCP in Active Mode), while in Passive Mode this is set by peer
    */
    void setSn_MSS(SOCKET s, uint16 Sn_MSSR)
    {
      IINCHIP_WRITE( Sn_MSSR0(s), (uint8)((Sn_MSSR & 0xff00) >> 8));
      IINCHIP_WRITE( Sn_MSSR1(s), (uint8)(Sn_MSSR & 0x00ff));
    }

    void setSn_TTL(SOCKET s, uint8 ttl)
    {   
       IINCHIP_WRITE( Sn_TTL(s) , ttl);
    }

     

    /**
    @brief  get socket interrupt status

    These below functions are used to read the Interrupt & Soket Status register
    */
    uint8 getSn_IR(SOCKET s)
    {
       return IINCHIP_READ(Sn_IR(s));
    }


    /**
    @brief   get socket status
    */
    uint8 getSn_SR(SOCKET s)
    {
       return IINCHIP_READ(Sn_SR(s));
    }


    /**
    @brief  get socket TX free buf size

    This gives free buffer size of transmit buffer. This is the data size that user can transmit.
    User shuold check this value first and control the size of transmitting data
    */
    uint16 getSn_TX_FSR(SOCKET s)
    {
      uint16 val=0,val1=0;
      do
      {
        val1 = IINCHIP_READ(Sn_TX_FSR0(s));
        val1 = (val1 << 8) + IINCHIP_READ(Sn_TX_FSR1(s));
          if (val1 != 0)
        {
            val = IINCHIP_READ(Sn_TX_FSR0(s));
            val = (val << 8) + IINCHIP_READ(Sn_TX_FSR1(s));
        }
      } while (val != val1);
       return val;
    }


    /**
    @brief   get socket RX recv buf size

    This gives size of received data in receive buffer.
    */
    uint16 getSn_RX_RSR(SOCKET s)
    {
      uint16 val=0,val1=0;
      do
      {
        val1 = IINCHIP_READ(Sn_RX_RSR0(s));
        val1 = (val1 << 8) + IINCHIP_READ(Sn_RX_RSR1(s));
        if(val1 != 0)
        {
            val = IINCHIP_READ(Sn_RX_RSR0(s));
            val = (val << 8) + IINCHIP_READ(Sn_RX_RSR1(s));
        }
      } while (val != val1);
       return val;
    }


    /**
    @brief   This function is being called by send() and sendto() function also.

    This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer
    register. User should read upper byte first and lower byte later to get proper value.
    */
    void send_data_processing(SOCKET s, uint8 *data, uint16 len)
    {
      if(len == 0)
      {
        //printf("CH: %d Unexpected1 length 0\r\n", s);
        return;
      }
      uint16 ptr = 0;
      uint32 addrbsb = 0;
     
      ptr = IINCHIP_READ( Sn_TX_WR0(s) );
      ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ(Sn_TX_WR1(s));
      addrbsb = ((uint32)ptr<<8) + (s<<5) + 0x10;
      wiz_write_buf(addrbsb, data, len);
     
      ptr += len;

      IINCHIP_WRITE( Sn_TX_WR0(s) ,(uint8)((ptr & 0xff00) >> 8));
      IINCHIP_WRITE( Sn_TX_WR1(s),(uint8)(ptr & 0x00ff)); 
    }


    /**
    @brief  This function is being called by recv() also.

    This function read the Rx read pointer register
    and after copy the data from receive buffer update the Rx write pointer register.
    User should read upper byte first and lower byte later to get proper value.
    */
    void recv_data_processing(SOCKET s, uint8 *data, uint16 len)
    {
      uint16 ptr = 0;
      uint32 addrbsb = 0;
     
      if(len == 0)
      {
        //printf("CH: %d Unexpected2 length 0\r\n", s);
        return;
      }

      ptr = IINCHIP_READ( Sn_RX_RD0(s) );
      ptr = ((ptr & 0x00ff) << 8) + IINCHIP_READ( Sn_RX_RD1(s) );

      addrbsb = ((uint32)ptr<<8) + (s<<5) + 0x18;
      wiz_read_buf(addrbsb, data, len);
      ptr += len;

      IINCHIP_WRITE( Sn_RX_RD0(s), (uint8)((ptr & 0xff00) >> 8));
      IINCHIP_WRITE( Sn_RX_RD1(s), (uint8)(ptr & 0x00ff));
    }

    void setSn_IR(uint8 s, uint8 val)
    {
        IINCHIP_WRITE(Sn_IR(s), val);
    }

     

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

     

    /*
    @file    w5500.h
    */
    #ifndef  _W5500_H_
    #define  _W5500_H_

    #include "Types.h"
    /**
     @brief Mode Register address
     * W5500 SPI Frame consists of 16bits Offset Address in Address Phase,
     * 8bits Control Phase and N bytes Data Phase.
     * 0                8                16               24                   ~
     * |----------------|----------------|----------------|----------------------
     * |        16bit offset Address     | Control Bits   |  Data Phase
     *
     * The 8bits Control Phase is reconfigured with Block Select bits (BSB[4:0]),
     * Read/Write Access Mode bit (RWB) and SPI Operation Mode (OM[1:0]).
     * Block Select bits select a block as like common register, socket register, tx buffer and tx buffer.
     * Address value is defined as 16bit offset Address, BSB[4:0] and the three bits of zero-padding.(The RWB and OM [1:0] are '0 'padding)
     * Please, refer to W5500 datasheet for more detail about Memory Map.
     *
     */

    /**
     @brief Mode Register address
     */
    #define MR                          (0x000000)

    /**
     @brief Gateway IP Register address
     */
    #define GAR0                        (0x000100)
    #define GAR1                        (0x000200)
    #define GAR2                        (0x000300)
    #define GAR3                        (0x000400)
    /**
     @brief Subnet mask Register address
     */
    #define SUBR0                       (0x000500)
    #define SUBR1                       (0x000600)
    #define SUBR2                       (0x000700)
    #define SUBR3                       (0x000800)

    /**
     @brief Source MAC Register address
     */
    #define SHAR0                       (0x000900)
    #define SHAR1                       (0x000A00)
    #define SHAR2                       (0x000B00)
    #define SHAR3                       (0x000C00)
    #define SHAR4                       (0x000D00)
    #define SHAR5                       (0x000E00)
    /**
     @brief Source IP Register address
     */
    #define SIPR0                       (0x000F00)
    #define SIPR1                       (0x001000)
    #define SIPR2                       (0x001100)
    #define SIPR3                       (0x001200)
    /**
     @brief set Interrupt low level timer register address
     */
    #define INTLEVEL0                   (0x001300)
    #define INTLEVEL1                   (0x001400)
    /**
     @brief Interrupt Register
     */
    #define IR                          (0x001500)
    /**
     @brief Interrupt mask register
     */
    #define IMR                         (0x001600)
    /**
     @brief Socket Interrupt Register
     */
    #define SIR                         (0x001700)
    /**
     @brief Socket Interrupt Mask Register
     */
    #define SIMR                        (0x001800)
    /**
     @brief Timeout register address( 1 is 100us )
     */
    #define RTR0                        (0x001900)
    #define RTR1                        (0x001A00)
    /**
     @brief Retry count reigster
     */
    #define WIZ_RCR                         (0x001B00)
    /**
     @briefPPP LCP Request Timer register  in PPPoE mode
     */
    #define PTIMER                      (0x001C00)
    /**
     @brief PPP LCP Magic number register  in PPPoE mode
     */
    #define PMAGIC                      (0x001D00)
    /**
     @brief PPP Destination MAC Register address
     */
    #define PDHAR0                      (0x001E00)
    #define PDHAR1                      (0x001F00)
    #define PDHAR2                      (0x002000)
    #define PDHAR3                      (0x002100)
    #define PDHAR4                      (0x002200)
    #define PDHAR5                      (0x002300)
    /**
     @brief PPP Session Identification Register
     */
    #define PSID0                       (0x002400)
    #define PSID1                       (0x002500)
    /**
     @brief PPP Maximum Segment Size(MSS) register
     */
    #define PMR0                        (0x002600)
    #define PMR1                        (0x002700)
    /**
     @brief Unreachable IP register address in UDP mode
     */
    #define UIPR0                       (0x002800)
    #define UIPR1                       (0x002900)
    #define UIPR2                       (0x002A00)
    #define UIPR3                       (0x002B00)
    /**
     @brief Unreachable Port register address in UDP mode
     */
    #define UPORT0                      (0x002C00)
    #define UPORT1                      (0x002D00)
    /**
     @brief PHY Configuration Register
     */
    #define PHYCFGR                      (0x002E00)
    /**
     @brief chip version register address
     */
    #define VERSIONR                    (0x003900)  

     

    /**
     @brief socket Mode register
     */
    #define Sn_MR(ch)                       (0x000008 + (ch<<5))

    /**
     @brief channel Sn_CR register
     */
    #define Sn_CR(ch)                       (0x000108 + (ch<<5))
    /**
     @brief channel interrupt register
     */
    #define Sn_IR(ch)                       (0x000208 + (ch<<5))
    /**
     @brief channel status register
     */
    #define Sn_SR(ch)                       (0x000308 + (ch<<5))
    /**
     @brief source port register
     */
    #define Sn_PORT0(ch)                    (0x000408 + (ch<<5))
    #define Sn_PORT1(ch)                    (0x000508 + (ch<<5))
    /**
     @brief Peer MAC register address
     */
    #define Sn_DHAR0(ch)                    (0x000608 + (ch<<5))
    #define Sn_DHAR1(ch)                    (0x000708 + (ch<<5))
    #define Sn_DHAR2(ch)                    (0x000808 + (ch<<5))
    #define Sn_DHAR3(ch)                    (0x000908 + (ch<<5))
    #define Sn_DHAR4(ch)                    (0x000A08 + (ch<<5))
    #define Sn_DHAR5(ch)                    (0x000B08 + (ch<<5))
    /**
     @brief Peer IP register address
     */
    #define Sn_DIPR0(ch)                    (0x000C08 + (ch<<5))
    #define Sn_DIPR1(ch)                    (0x000D08 + (ch<<5))
    #define Sn_DIPR2(ch)                    (0x000E08 + (ch<<5))
    #define Sn_DIPR3(ch)                    (0x000F08 + (ch<<5))
    /**
     @brief Peer port register address
     */
    #define Sn_DPORT0(ch)                   (0x001008 + (ch<<5))
    #define Sn_DPORT1(ch)                   (0x001108 + (ch<<5))
    /**
     @brief Maximum Segment Size(Sn_MSSR0) register address
     */
    #define Sn_MSSR0(ch)                    (0x001208 + (ch<<5))
    #define Sn_MSSR1(ch)                    (0x001308 + (ch<<5))
    /**
     @brief IP Type of Service(TOS) Register
     */
    #define Sn_TOS(ch)                      (0x001508 + (ch<<5))
    /**
     @brief IP Time to live(TTL) Register
     */
    #define Sn_TTL(ch)                      (0x001608 + (ch<<5))
    /**
     @brief Receive memory size reigster
     */
    #define Sn_RXMEM_SIZE(ch)               (0x001E08 + (ch<<5))
    /**
     @brief Transmit memory size reigster
     */
    #define Sn_TXMEM_SIZE(ch)               (0x001F08 + (ch<<5))
    /**
     @brief Transmit free memory size register
     */
    #define Sn_TX_FSR0(ch)                  (0x002008 + (ch<<5))
    #define Sn_TX_FSR1(ch)                  (0x002108 + (ch<<5))
    /**
     @brief Transmit memory read pointer register address
     */
    #define Sn_TX_RD0(ch)                   (0x002208 + (ch<<5))
    #define Sn_TX_RD1(ch)                   (0x002308 + (ch<<5))
    /**
     @brief Transmit memory write pointer register address
     */
    #define Sn_TX_WR0(ch)                   (0x002408 + (ch<<5))
    #define Sn_TX_WR1(ch)                   (0x002508 + (ch<<5))
    /**
     @brief Received data size register
     */
    #define Sn_RX_RSR0(ch)                  (0x002608 + (ch<<5))
    #define Sn_RX_RSR1(ch)                  (0x002708 + (ch<<5))
    /**
     @brief Read point of Receive memory
     */
    #define Sn_RX_RD0(ch)                   (0x002808 + (ch<<5))
    #define Sn_RX_RD1(ch)                   (0x002908 + (ch<<5))
    /**
     @brief Write point of Receive memory
     */
    #define Sn_RX_WR0(ch)                   (0x002A08 + (ch<<5))
    #define Sn_RX_WR1(ch)                   (0x002B08 + (ch<<5))
    /**
     @brief socket interrupt mask register
     */
    #define Sn_IMR(ch)                      (0x002C08 + (ch<<5))
    /**
     @brief frag field value in IP header register
     */
    #define Sn_FRAG(ch)                     (0x002D08 + (ch<<5))
    /**
     @brief Keep Timer register
     */
    #define Sn_KPALVTR(ch)                  (0x002F08 + (ch<<5))

    /* MODE register values */
    #define MR_RST                       0x80 /**< reset */
    #define MR_WOL                       0x20 /**< Wake on Lan */
    #define MR_PB                        0x10 /**< ping block */
    #define MR_PPPOE                     0x08 /**< enable pppoe */
    #define MR_UDP_FARP                  0x02 /**< enbale FORCE ARP */


    /* IR register values */
    #define IR_CONFLICT                  0x80 /**< check ip confict */
    #define IR_UNREACH                   0x40 /**< get the destination unreachable message in UDP sending */
    #define IR_PPPoE                     0x20 /**< get the PPPoE close message */
    #define IR_MAGIC                     0x10 /**< get the magic packet interrupt */

    /* Sn_MR values */
    #define Sn_MR_CLOSE                  0x00     /**< unused socket */
    #define Sn_MR_TCP                    0x01     /**< TCP */
    #define Sn_MR_UDP                    0x02     /**< UDP */
    #define Sn_MR_IPRAW                  0x03      /**< IP LAYER RAW SOCK */
    #define Sn_MR_MACRAW                 0x04      /**< MAC LAYER RAW SOCK */
    #define Sn_MR_PPPOE                  0x05     /**< PPPoE */
    #define Sn_MR_UCASTB                 0x10     /**< Unicast Block in UDP Multicating*/
    #define Sn_MR_ND                     0x20     /**< No Delayed Ack(TCP) flag */
    #define Sn_MR_MC                     0x20     /**< Multicast IGMP (UDP) flag */
    #define Sn_MR_BCASTB                 0x40     /**< Broadcast blcok in UDP Multicating */
    #define Sn_MR_MULTI                  0x80     /**< support UDP Multicating */

     /* Sn_MR values on MACRAW MODE */
    #define Sn_MR_MIP6N                  0x10     /**< IPv6 packet Block */
    #define Sn_MR_MMB                    0x20     /**< IPv4 Multicasting Block */
    //#define Sn_MR_BCASTB                 0x40     /**< Broadcast blcok */
    #define Sn_MR_MFEN                   0x80     /**< support MAC filter enable */


    /* Sn_CR values */
    #define Sn_CR_OPEN                   0x01     /**< initialize or open socket */
    #define Sn_CR_LISTEN                 0x02     /**< wait connection request in tcp mode(Server mode) */
    #define Sn_CR_CONNECT                0x04     /**< send connection request in tcp mode(Client mode) */
    #define Sn_CR_DISCON                 0x08     /**< send closing reqeuset in tcp mode */
    #define Sn_CR_CLOSE                  0x10     /**< close socket */
    #define Sn_CR_SEND                   0x20     /**< update txbuf pointer, send data */
    #define Sn_CR_SEND_MAC               0x21     /**< send data with MAC address, so without ARP process */
    #define Sn_CR_SEND_KEEP              0x22     /**<  send keep alive message */
    #define Sn_CR_RECV                   0x40     /**< update rxbuf pointer, recv data */

    #ifdef __DEF_IINCHIP_PPP__
       #define Sn_CR_PCON                0x23     
       #define Sn_CR_PDISCON             0x24     
       #define Sn_CR_PCR                 0x25     
       #define Sn_CR_PCN                 0x26    
       #define Sn_CR_PCJ                 0x27    
    #endif

    /* Sn_IR values */
    #ifdef __DEF_IINCHIP_PPP__
       #define Sn_IR_PRECV               0x80    
       #define Sn_IR_PFAIL               0x40    
       #define Sn_IR_PNEXT               0x20    
    #endif

    #define Sn_IR_SEND_OK                0x10     /**< complete sending */
    #define Sn_IR_TIMEOUT                0x08     /**< assert timeout */
    #define Sn_IR_RECV                   0x04     /**< receiving data */
    #define Sn_IR_DISCON                 0x02     /**< closed socket */
    #define Sn_IR_CON                    0x01     /**< established connection */

    /* Sn_SR values */
    #define SOCK_CLOSED                  0x00     /**< closed */
    #define SOCK_INIT                    0x13     /**< init state */
    #define SOCK_LISTEN                  0x14     /**< listen state */
    #define SOCK_SYNSENT                 0x15     /**< connection state */
    #define SOCK_SYNRECV                 0x16     /**< connection state */
    #define SOCK_ESTABLISHED             0x17     /**< success to connect */
    #define SOCK_FIN_WAIT                0x18     /**< closing state */
    #define SOCK_CLOSING                 0x1A     /**< closing state */
    #define SOCK_TIME_WAIT               0x1B     /**< closing state */
    #define SOCK_CLOSE_WAIT              0x1C     /**< closing state */
    #define SOCK_LAST_ACK                0x1D     /**< closing state */
    #define SOCK_UDP                     0x22     /**< udp socket */
    #define SOCK_IPRAW                   0x32     /**< ip raw mode socket */
    #define SOCK_MACRAW                  0x42     /**< mac raw mode socket */
    #define SOCK_PPPOE                   0x5F     /**< pppoe socket */

    /* IP PROTOCOL */
    #define IPPROTO_IP                   0        /**< Dummy for IP */
    #define IPPROTO_ICMP                 1        /**< Control message protocol */
    #define IPPROTO_IGMP                 2        /**< Internet group management protocol */
    #define IPPROTO_GGP                  3        /**< Gateway^2 (deprecated) */
    #define IPPROTO_TCP                  6        /**< TCP */
    #define IPPROTO_PUP                  12       /**< PUP */
    #define IPPROTO_UDP                  17       /**< UDP */
    #define IPPROTO_IDP                  22       /**< XNS idp */
    #define IPPROTO_ND                   77       /**< UNOFFICIAL net disk protocol */
    #define IPPROTO_RAW                  255      /**< Raw IP packet */

    /*********************************************************
    * iinchip access function
    *********************************************************/
    void IINCHIP_WRITE( uint32 addrbsb,  uint8 data);
    uint8 IINCHIP_READ(uint32 addrbsb);
    uint16 wiz_write_buf(uint32 addrbsb,uint8* buf,uint16 len);
    uint16 wiz_read_buf(uint32 addrbsb, uint8* buf,uint16 len);


    void iinchip_init(void); // reset iinchip
    void sysinit(uint8 * tx_size, uint8 * rx_size); // setting tx/rx buf size
    uint8 getISR(uint8 s);
    void putISR(uint8 s, uint8 val);
    uint16 getIINCHIP_RxMAX(uint8 s);
    uint16 getIINCHIP_TxMAX(uint8 s);
    void setMR(uint8 val);
    void setRTR(uint16 timeout); // set retry duration for data transmission, connection, closing ...
    void setRCR(uint8 retry); // set retry count (above the value, assert timeout interrupt)
    void clearIR(uint8 mask); // clear interrupt
    uint8 getIR( void );
    void setSn_MSS(SOCKET s, uint16 Sn_MSSR); // set maximum segment size
    uint8 getSn_IR(SOCKET s); // get socket interrupt status
    uint8 getSn_SR(SOCKET s); // get socket status
    uint16 getSn_TX_FSR(SOCKET s); // get socket TX free buf size
    uint16 getSn_RX_RSR(SOCKET s); // get socket RX recv buf size
    uint8 getSn_SR(SOCKET s);
    void setSn_TTL(SOCKET s, uint8 ttl);
    void send_data_processing(SOCKET s, uint8 *wizdata, uint16 len);
    void recv_data_processing(SOCKET s, uint8 *wizdata, uint16 len);

    void setGAR(uint8 * addr); // set gateway address
    void setSUBR(uint8 * addr); // set subnet mask address
    void setSHAR(uint8 * addr); // set local MAC address
    void setSIPR(uint8 * addr); // set local IP address
    void getGAR(uint8 * addr);
    void getSUBR(uint8 * addr);
    void getSHAR(uint8 * addr);
    void getSIPR(uint8 * addr);

    void setSn_IR(uint8 s, uint8 val);
    /**
     @brief WIZCHIP_OFFSET_INC on IINCHIP_READ/WRITE
     * case1.
     *  IINCHIP_WRITE(RTR0,val);
     *  IINCHIP_WRITE(RTR1,val);
     * case1.
     *  IINCHIP_WRITE(RTR0,val);
     *  IINCHIP_WRITE(WIZCHIP_OFFSET_INC(RTR0,1));
     */
    //#define WIZCHIP_OFFSET_INC(ADDR, N)    (ADDR + (N<<8)) //< Increase offset address

    #endif


     

    展开全文
  • 之前那篇写w5500驱动只是单纯的应用程序驱动,虽然可以实现一定的目的,但是没有充分利用到linux的内核,在一些应用场合就显得不合时宜,于是就进行w5500网络设备内核驱动的学习,幸运的是w5500网络设备驱动的文件是...

           之前那篇写w5500驱动只是单纯的应用程序驱动,虽然可以实现一定的目的,但是没有充分利用到linux的内核,在一些应用场合就显得不合时宜,于是就进行w5500网络设备内核驱动的学习,幸运的是w5500网络设备驱动的文件是在4.8版本的linux内核中找到,但是与我现在使用的2.6.33版本的内核在有些函数和数据结构等都有一定程度上缺失,为此花了很久的一段时间去修修补补这个驱动C文件,终于修补到了编译无错误的程度了,但也经过一定时间的调试才能达到想要的效果,但是通过这样也学习到linux的网络设备方面的知识
           这里只是对w5500网络设备驱动的一些重要的函数及数据结构做简单的分析与总结
           W5500网络设备驱动主要包括在两个文件:w5500.cw5500-spi.c
           w5100-spi.c构建spi设备驱动以使用spi接口方式来设置w5500,设置w5500的基本读写函数,w5100.c主要构建linux内核的网络设备驱动,设置网络发送接收skb等函数,注意两者紧密相连,缺一不可!修改内核文件中的Kconfig和makefile文件编译这两个C文件。
    基本流程为:


    这里写图片描述

           在w5100-spi.c主要是用spi的方式来设置w5500的读、写函数,通过其中的w5100_spi_probe函数最后转入到w5100.c中的w5100_probe函数,下面重点关注w5100_spi_probe()这个函数:

    int w5100_probe(struct device *dev, const struct w5100_ops *ops,int sizeof_ops_priv, const void *mac_addr, int irq,int link_gpio)

    1、 进入这个函数后,首先分配注册网络设备
    ndev = alloc_etherdev(alloc_size);
    err = register_netdev(ndev);

    2、 填充网络设备文件操作结构体
    ndev->netdev_ops = &w5100_netdev_ops;

    static const struct net_device_ops w5100_netdev_ops = {
    .ndo_open = w5100_open,
    .ndo_stop = w5100_stop,
    .ndo_start_xmit = w5100_start_tx,
    .ndo_tx_timeout = w5100_tx_timeout,
    .ndo_set_rx_mode = w5100_set_rx_mode,
    .ndo_set_mac_address = w5100_set_macaddr,
    .ndo_validate_addr = eth_validate_addr,
    .ndo_change_mtu = eth_change_mtu,
    };
    填充网络设备文件操作,open、stop、.ndo_start_xmit等函数,可见网络设备数据发送函数为w5100_start_tx

    3、 填充ethtool_ops结构体
    ndev->ethtool_ops = &w5100_ethtool_ops;

      static const struct ethtool_ops w5100_ethtool_ops = {
    .get_drvinfo        = w5100_get_drvinfo,
    .get_msglevel       = w5100_get_msglevel,
    .set_msglevel       = w5100_set_msglevel,
    .get_link       = w5100_get_link,
    .get_regs_len       = w5100_get_regs_len,
    .get_regs       = w5100_get_regs,
    

    };
           ethtool_ops成员函数与用户空间ethool工具的各个命令选项对应,ethtool提供了网卡及网卡驱动管理能力,能够为linux网络开发人员和管理人员提供对网卡硬件、驱动程序和网络协议栈的设置、查看以及调试等功能。

    4、 netif_napi_add(ndev, &priv->napi, w5100_napi_poll, 16);
           该函数用于初始化一个NAPI,netif_napi_add()的poll参数是NAPI要调度执行的轮询函数
    数据接收流程:


    这里写图片描述

           如果是NAPI兼容的设备驱动,则通过poll方式接收数据包,在这种情况下,我们需要为该设备驱动提供作为netif_napi_add()参数的w5100_napi_poll函数:

    static int w5100_napi_poll(struct napi_struct *napi, int budget)
    {
              struct w5100_priv *priv = container_of(napi, struct w5100_priv, napi);
        int rx_count;
    
        for (rx_count = 0; rx_count < budget; rx_count++) {
            struct sk_buff *skb = w5100_rx_skb(priv->ndev); //取得接收skb的数据
    
            if (skb)
                netif_receive_skb(skb);//分析网络接收缓冲区的数据
            else
                break;
        }
    
        if (rx_count < budget) {
            napi_complete(napi);//将napi设备从轮询列表中删除
            w5100_enable_intr(priv); //使能中断
        }
    
        return rx_count;
    }

           数据接收的方式是NAPI(New API),简单来说,NAPI是综合中断方式与轮询方式的技术
    其数据接收流程为:
    接收中断来临——》关闭接收中断——》以轮询方式接收所有数据包直到收空——》开启接收中断——》接收中断来临

    注册中断函数:
    err = request_irq(priv->irq, w5100_interrupt,IRQF_TRIGGER_LOW, ndev->name, ndev);
           priv->irq:要申请的硬件中断号
           w5100_interrupt:向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,ndev参数将被传递给它
           IRQF_TRIGGER_LOW:指定中断触发类型:低电平有效
           ndev->name:设备驱动程序的名称
           ndev:中断名称可作为共享中断时的中断区别参数,也可以用来指定中断服务函数需要参考的数据地址

    中断函数:

    static irqreturn_t w5100_interrupt(int irq, void *ndev_instance)
    {
    struct net_device *ndev = ndev_instance;
    struct w5100_priv *priv = netdev_priv(ndev);
    
    int ir = w5100_read(priv, W5100_S0_IR(priv));
    if (!ir)
    return IRQ_NONE;
    w5100_write(priv, W5100_S0_IR(priv), ir);
    
    if (ir & S0_IR_SENDOK) {
    //      netif_dbg(priv, tx_done, ndev, "tx done\n");
    netif_wake_queue(ndev);
    }
    
    if (ir & S0_IR_RECV) {
    w5100_disable_intr(priv);
    
    if (priv->ops->may_sleep)
    queue_work(priv->xfer_wq, &priv->rx_work); //调度执行一个指定workqueue中的任务。输入参数:
    @ workqueue_struct:指定的workqueue指针
    @work_struct:具体任务对象指针
    
    else if (napi_schedule_prep(&priv->napi)) //检查是否可以进行napi调度
    __napi_schedule(&priv->napi);// 在网卡驱动的中断处理函数中调用napi_schedule()来使用NAPI
    }
    
    return IRQ_HANDLED;
    }

    5、 创建网卡工作队列
           priv->xfer_wq = alloc_workqueue(netdev_name(ndev), WQ_MEM_RECLAIM, 0);

    添加四个任务到工作队列
           INIT_WORK(&priv->rx_work, w5100_rx_work);
           INIT_WORK(&priv->tx_work, w5100_tx_work);
           INIT_WORK(&priv->setrx_work, w5100_setrx_work);
           INIT_WORK(&priv->restart_work, w5100_restart_work);

           INIT_WORK会在你定义的_work工作队列里面增加一个工作任务,该任务就是_func。_func这个任务会需要一些数据作为参数,这个参数就是通过_data传递的。
    ⑴w5100_rx_work()函数:
    w5100_rx_skb():
    ①skb = netdev_alloc_skb_ip_align(ndev, rx_len);
           netdev_alloc_skb_ip_align会申请一个sk_buff结构,同时申请存放报文数据的buffer空间,并将他们关联起来
    ②skb_put(skb, rx_len);
           skb_put()修改指向数据区末尾的指针tail,使之往下移len字节,即使数据区向下扩大len字节,并更新数据区长度len,通常在设备驱动的接收数据处理中会调用此函数。
    ③skb->protocol = eth_type_trans(skb, ndev);
           Linux kernel使用eth_type_trans来判断数据帧的类型,及协议类型

    w5100_enable_intr(priv):使能中断

    ⑵w5100_tx_work()函数:w5100_tx_skb,发送写入skb的函数,最后dev_kfree_skb(skb)释放套接字缓冲区。

    ⑶w5100_setrx_work(struct work_struct *work)
           w5100_hw_start(priv):w5500硬件启动
           u8 mode = S0_MR_MACRAW;//将w5500设置为原始套接字,此处关键!

    ⑷w5100_restart_work
           w5100_restart:
    ①netif_stop_queue(ndev):
           调用linux内核提供的netif_stop_queue()函数,停止设备传输包。
    ②w5100_hw_reset(priv);
            函数内对w5500设置mac地址,进行socket0的初始化
    ③netif_wake_queue(ndev);
            当忙于发送的数据包被发送完成后,在以TX结束的中断处理中,应该调用netif_wake_queue(ndev)唤醒被阻塞的上层,以启动它继续向网络设备驱动传送数据包。

    6、 数据发送函数
    w5100_netdev_ops函数中.ndo_start_xmit = w5100_start_tx,所以w5100_start_tx()为网卡数据发送函数

    static int w5100_start_tx(struct sk_buff *skb, struct net_device *ndev)
    {
        struct w5100_priv *priv = netdev_priv(ndev);
    
        netif_stop_queue(ndev);// 停止设备传输包
    
        if (priv->ops->may_sleep) {
            WARN_ON(priv->tx_skb);
            priv->tx_skb = skb;
            queue_work(priv->xfer_wq, &priv->tx_work);//开启数据发送工作任务
        } else {
            w5100_tx_skb(ndev, skb);
        }
    
        return NETDEV_TX_OK;
    }
    static void w5100_tx_skb(struct net_device *ndev, struct sk_buff *skb)
    {
        struct w5100_priv *priv = netdev_priv(ndev);
        u16 offset;
    
        offset = w5100_read16(priv, W5100_S0_TX_WR(priv));//读w5500的socket0发送缓冲区偏移
        w5100_writebuf(priv, offset, skb->data, skb->len);
        w5100_write16(priv, W5100_S0_TX_WR(priv), offset + skb->len);//写数据到w5500
        ndev->stats.tx_bytes += skb->len;
        ndev->stats.tx_packets++; //记录发包数量
        dev_kfree_skb(skb);
    
        w5100_command(priv, S0_CR_SEND);
    }

    最后运行的效果:


    这里写图片描述
           设置w5500网卡ip地址为192.168.1.88,用电脑主机去ping,可以ping通,若在linux内核中加了tcp/ip协议栈的话,则可以与电脑主机服务器进行tcp和udp连接,但是这样却没有使用w5500原本自带的硬件tcp/ip协议栈,而是直接绕过去了,我们注意到的是w5500的网络设备驱动程序是设置为原始套接字的形式,所以以后要关注的原始套接字在网络协议中的传输!!

    展开全文
  • 针对以太网通信芯片W5500设计,市面上比较常见的是c语言完成驱动开发和应用设计, 该部分程序是FPGA Verilog语言编写,已成功应用在项目中,不接受不好用的差评,注释清晰,是你工程开发,学习的利器。
  • W5500移植讲解.rar、iolibrary_bsd_ethernet_v103(close函数需要更改).zip
  • 1.关于 ioLibrary_Driver1.1. ioLibrary 概述The ioLibrary means “Internet Offload Library” for WIZnet chip. It includes drivers and application protocols. The driver (ioLibrary) can be used for the ...
    1.关于 ioLibrary_Driver
    1.1. ioLibrary 概述
    The ioLibrary means “Internet Offload Library” for WIZnet chip. It includes drivers and application protocols. The driver (ioLibrary) can be used for the application design of WIZnet TCP/IP chips as W5500, W5300, W5200 and W5100.
    更多信息参考ioLibrary的 wiki : http://wizwiki.net/wiki/doku.php?id=products:w5500:driver
    1.2. ioLibrary 下载
    从 github ( https://github.com/Wiznet/ioLibrary_Driver ) 下载驱动库
    2. ioLibrary 移植STM32F4
    2.1. 准备工作
    首先,下载库源码,解压,文件目录如下所示:

    然后,准备一个基本的STM32F4的工程,将 ioLibrary_Driver 放到工程目录下。

    2.2. 移植过程
    步骤一、将用到 ioLibrary_Driver\Ethernet 下面的文件,将这些文件加入到自己的工程中。

    步骤二、添加对应的头文件目录到工程中。


    然后编译,出现如下错误,将问题行注释掉。


    若编译出现类似于如下错误
    ..\User\Ethernet\wizchip_conf.c(113): error:  #29: expected an expression
            .id                  = _WIZCHIP_ID_,
    ..\User\Ethernet\wizchip_conf.c(114): error:  #29: expected an expression
            .if_mode             = _WIZCHIP_IO_MODE_,
    ..\User\Ethernet\wizchip_conf.c(115): error:  #29: expected an expression
            .CRIS._enter         = wizchip_cris_enter,
    ..\User\Ethernet\wizchip_conf.c(116): error:  #29: expected an expression
            .CRIS._exit          = wizchip_cris_exit,
    ..\User\Ethernet\wizchip_conf.c(117): error:  #29: expected an expression
            .CS._select          = wizchip_cs_select,
    ..\User\Ethernet\wizchip_conf.c(118): error:  #29: expected an expression
            .CS._deselect        = wizchip_cs_deselect,
    ..\User\Ethernet\wizchip_conf.c(119): error:  #29: expected an expression
            .IF.BUS._read_byte   = wizchip_bus_readbyte,
    ..\User\Ethernet\wizchip_conf.c(120): error:  #29: expected an expression
            .IF.BUS._write_byte  = wizchip_bus_writebyte
    ..\User\Ethernet\wizchip_conf.c(123): warning:  #12-D: parsing restarts here after previous syntax error
            };
    ..\User\Ethernet\wizchip_conf.c: 1 warning, 8 errors
    主要原因是Keil MDK默认设置不支持按照结构体名称初始化结构体的原因导致。则需要根据自己的编译器做下设置,keil MDK设置如下所示:

    直到编译全部通过,编译器无错误,无警告提示。
    步骤三、W5500和STM32F4是通过SPI接口通信的,所以要配置底层SPI管脚功能及SPI工作模式。
    /**
    * @brief : WIZ_SPI_Init
    * @note : SPI接口初始化
    * 硬件连接: PA3 -> W5500_RST
    * PA4 -> W5500_SCS
    * PA5 -> W5500_SCK
    * PA6 -> W5500_MISO
    * PA7 -> W5500_MOSI
    * PA8 -> W5500_INT
    * @param :
    * @retval :
    */
    static void W5500_SPI_Init(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能GPIOA时钟

    /* W5500_RST引脚初始化配置(PA2) */
    GPIO_InitStructure.GPIO_Pin = W5500_RST;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
    GPIO_Init(W5500_RST_PORT, &GPIO_InitStructure);
    GPIO_SetBits(W5500_RST_PORT, W5500_RST); // 设置高电平,W5500不会进入复位模式

    /* 初始化CS引脚 */
    GPIO_InitStructure.GPIO_Pin = W5500_SCS;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(W5500_SCS_PORT, &GPIO_InitStructure);
    GPIO_SetBits(W5500_SCS_PORT, W5500_SCS);

    // Enable SPI and GPIO clocks
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);
    //SPI口初始化 Set PA5,6,7 as Output push-pull - SCK, MISO and MOSI
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    SPI_I2S_DeInit(SPI1);
    //初始化SPI结构体
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI设置为两线全双工
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收8位帧结构
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //串行时钟在不操作时,时钟为低电平
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //第一个时钟沿开始采样数据
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由软件(使用SSI位)管理
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; //SPI波特率预分频值为 2
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始
    SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI为主模式
    SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPI1寄存器
    SPI_Cmd(SPI1, DISABLE);
    /* Enable SPI1 */ //使能SPI外设
    SPI_Cmd(SPI1, ENABLE); //启动传输
    }
    步骤四、在 wizchip_conf.h 文件中,有以下几个功能回调注册函数:
    void reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void));
    void reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void));
    void reg_wizchip_bus_cbfunc(iodata_t (*bus_rb)(uint32_t addr), void (*bus_wb)(uint32_t addr, iodata_t wb));
    void reg_wizchip_spi_cbfunc(uint8_t (*spi_rb)(void), void (*spi_wb)(uint8_t wb));
    void reg_wizchip_spiburst_cbfunc(void (*spi_rb)(uint8_t* pBuf, uint16_t len), void (*spi_wb)(uint8_t* pBuf, uint16_t len));
    根据以上几个接口设定的函数接口,添加如下代码
    /**
    * @brief : WIZ_CS
    * @note : 选择W5500
    * @param :
    * @retval :
    */
    static void W5500_CS_Select(void)
    {
    GPIO_ResetBits(W5500_SCS_PORT, W5500_SCS);//置W5500的SCS为低电平
    }
    /**
    * @brief : SPI_CS_Deselect
    * @note : 去选择W5500
    * @param :
    * @retval :
    */
    static void W5500_CS_Deselect(void)
    {
    GPIO_SetBits(W5500_SCS_PORT, W5500_SCS); //置W5500的SCS为高电平
    }

    /**
    * @brief : W5500_WriteByte
    * @note : W5500 写
    * @param :
    * @retval :
    */
    static void W5500_WriteByte(uint8_t byte)
    {
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, byte);

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    SPI_I2S_ReceiveData(SPI1);
    }

    /**
    * @brief : W5500_ReadByte
    * @note : W5500 读
    * @param :
    * @retval :
    */
    static uint8_t W5500_ReadByte(void)
    {
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI1, 0xFF);

    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    return (SPI_I2S_ReceiveData(SPI1));
    }

    步骤五、W5500正常工作还需配置MAC地址,IP地址,子网掩码等网络配置信息。
    /**
    * @brief : W5500_Network_Init
    * @note : W5500 网络初始化
    * @param :
    * @retval :
    */
    static void W5500_Network_Init(void)
    {
    uint8_t chipid[6];
    wiz_NetInfo gWIZNETINFO;
    uint8_t mac[6]={0x00,0x08,0xdc,0x11,0x11,0x11}; ///< Source Mac Address
    uint8_t ip[4]={192,168,100,150}; ///< Source IP Address
    uint8_t sn[4]={255,255,255,0}; ///< Subnet Mask
    uint8_t gw[4]={192,168,100,1}; ///< Gateway IP Address
    uint8_t dns[4]={8,8,8,8}; ///< DNS server IP Address

    memcpy(gWIZNETINFO.ip, ip, 4);
    memcpy(gWIZNETINFO.sn, sn, 4);
    memcpy(gWIZNETINFO.gw, gw, 4);
    memcpy(gWIZNETINFO.mac, mac,6);
    memcpy(gWIZNETINFO.dns,dns,4);
    gWIZNETINFO.dhcp = NETINFO_STATIC; //< 1 - Static, 2 - DHCP
    ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);

    ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);
    // Display Network Information
    ctlwizchip(CW_GET_ID,(void*)chipid);
    printf("\r\n=== %s NET CONF ===\r\n",(char*)chipid);
    printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n",gWIZNETINFO.mac[0],gWIZNETINFO.mac[1],gWIZNETINFO.mac[2],
    gWIZNETINFO.mac[3],gWIZNETINFO.mac[4],gWIZNETINFO.mac[5]);
    printf("SIP: %d.%d.%d.%d\r\n", gWIZNETINFO.ip[0],gWIZNETINFO.ip[1],gWIZNETINFO.ip[2],gWIZNETINFO.ip[3]);
    printf("GAR: %d.%d.%d.%d\r\n", gWIZNETINFO.gw[0],gWIZNETINFO.gw[1],gWIZNETINFO.gw[2],gWIZNETINFO.gw[3]);
    printf("SUB: %d.%d.%d.%d\r\n", gWIZNETINFO.sn[0],gWIZNETINFO.sn[1],gWIZNETINFO.sn[2],gWIZNETINFO.sn[3]);
    printf("DNS: %d.%d.%d.%d\r\n", gWIZNETINFO.dns[0],gWIZNETINFO.dns[1],gWIZNETINFO.dns[2],gWIZNETINFO.dns[3]);
    printf("======================\r\n");

    wizchip_init(NULL, NULL);

    wiz_NetTimeout w_NetTimeout;
    w_NetTimeout.retry_cnt = 50;
    w_NetTimeout.time_100us = 1000;
    wizchip_settimeout(&w_NetTimeout);
    }
    步骤六、初始化W5500相关设定。
    /**
    * @brief : W5500_Init
    * @note : 初始化
    * @param :
    * @retval :
    */
    void W5500_Init(void)
    {
    W5500_SPI_Init();

    for(int i=0x5FFF; i>0; i--); // 短暂延时,不然导致初始化失败

    reg_wizchip_cris_cbfunc(NULL, NULL); // 注册临界区函数
    reg_wizchip_cs_cbfunc(W5500_CS_Select, W5500_CS_Deselect);// 注册片选函数
    reg_wizchip_spi_cbfunc(W5500_ReadByte, W5500_WriteByte); // 注册读写函数

    W5500_Network_Init();
    }

    步骤七、到这里,移植基本上完成。编译工程保证无错误,无警告输出。
    3. 基于ioLibrary的应用
    3.1. 功能测试
    步骤一、将用到 ioLibrary_Driver\Application 的文件添加到工程

    步骤二、包含对应头文件路径。

    步骤三、添加应用代码到主流程中。
    /**
    * @brief Main program
    * @param None
    * @retval None
    */
    int main(void)
    {
    uint8_t dest_ip[4] = {192, 168, 10, 13};
    uint16_t dest_port = 8080;

    uint8_t dataBuffer[DATA_BUF_SIZE]={0x0};

    RCC_ClocksTypeDef RCC_Clocks;

    /* SysTick end of count event each 10ms */
    RCC_GetClocksFreq(&RCC_Clocks);
    SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000);

    /* Add your application code here */

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    USART1_NVIC_Config(0,1);

    LED_Init();
    USART1_Init();
    W5500_Init();
    /* Infinite loop */
    while (1)
    {
    loopback_tcpc(0x0, dataBuffer, dest_ip, dest_port);
    LEDA_ON;LEDB_OFF;
    Delay(50);
    LEDA_OFF;LEDB_ON;
    Delay(50);
    }
    }
    步骤四、调整工程堆栈配置(根据功能需要,自定大小)。

    步骤五、启动网络调试助手,适当配置。

    步骤六、编译程序,烧写到单片机中,重启。查看连接对象中是否出现,TCP-Client,选择点击发送按钮,能收到回文,代表测试成功。

    3.2. ping 测试
    我们ping下程序里面的IP试试,能ping通,看来没什么大问题了。

    4、测试代码
    CSDN下载链接:https://download.csdn.net/download/xiayufeng520/10293822




    展开全文
  • 使用w5500的目的是领导... 继上文添加好Uclinux的spidev驱动后,spi1的miso、mosi、clk、cs等接口已经能正常输出数据,确保了这些以后,我们就可以使用W5500这个网络模块来进行udp、tcp通信连接了。 w5500模块类似

           使用w5500的目的是领导要求能从下位机通过tcp或者udp的形式把数据发到服务器上面去,进而把数据显示在服务器的网页上和传到手机的app上面显示。

           继上文添加好Uclinux的spidev驱动后,spi1的miso、mosi、clk、cs等接口已经能正常输出数据,确保了这些以后,我们就可以使用W5500这个网络模块来进行udp、tcp通信连接了。
           w5500模块类似于一个网卡,它里面用硬件集成有tcp/ip协议这样就不需要在Uclinux内核里再添加tcp协议栈(占用空间很大,现在使用的板子内存吃不消),而且操作方便,只需设置好w5500的ip地址、子网掩码、网关等,设置好它里面的socket(共有八个socket),无需繁杂的socket编程,设置好即可进行tcp、udp通信连接,而要设置好上面所说的这些玩意,一定是要用spi来设置,上一篇文章的spi驱动就为了这个目的。
           经过上文的步骤后,我们可以放心的编写一个应用程序来实现w5500的相关设置与tcp或者udp连接。
           这个应用程序最关键的就是spi的读写函数的实现,在参照了官方的spi读写应用程序,自己稍加修改后写的spi读写函数:
    1、写函数:

    void IINCHIP_WRITE( uint32 addrbsb,  uint8 data,int fd)
    {
    
        struct spi_ioc_transfer xfer[2];
        unsigned char buf[2048], *bp;
        int len, status;
    
        memset(xfer, 0, sizeof xfer);
        memset(buf, 0, sizeof buf);
        len = sizeof buf;
    
       buf[0] = (addrbsb & 0x00FF0000)>>16;
       buf[1] = (addrbsb & 0x0000FF00)>> 8;
       buf[2] = (addrbsb & 0x000000F8) + 4;
       buf[3] =  data;
    
       xfer[0].tx_buf = (unsigned long)buf;
       xfer[0].len = 4;
    
       status = ioctl(fd, SPI_IOC_MESSAGE(1), xfer);
    
    if (status < 0) {
    perror("SPI_IOC_MESSAGE");
    return;
    }   
    
    }
    

    2、读函数:

    uint8 IINCHIP_READ(uint32 addrbsb,int fd)
    {
       uint8 data = 0;
       struct spi_ioc_transfer xfer[2];
        unsigned char buf[2048], *bp;
        int len, status;
    
        memset(xfer, 0, sizeof xfer);
        memset(buf, 0, sizeof buf);
        len = sizeof buf;
    
    
          buf[0] = (addrbsb & 0x00FF0000)>>16;
          buf[1] = (addrbsb & 0x0000FF00)>> 8;
          buf[2] = (addrbsb & 0x000000F8) ;
    
                len = 3;
                xfer[0].tx_buf = (unsigned long)buf;
                xfer[0].len = 3;
    
    
                xfer[1].rx_buf = (unsigned long) buf;
                xfer[1].len = 3;
    
                status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
                if (status < 0) {
                perror("SPI_IOC_MESSAGE");
                return;
                }
    
    
    }

           关键的读写函数解决了,然后就可以利用读写函数来读写w5500里面的寄存器,进而设置w5500的ip地址、子网掩码、网关、端口号等,设置好它里面的socket(这些设置繁多程序不便列出,建议参照w5500的官方pdf来进行相关设置,我是从某网站下载了stm32f4的w5500 tcp/udp的keil工程文件,然后参照pdf来编写修改代码),从而实现tcp或者udp的通信连接。
           编写好应用程序后,编译无错误后生成可执行文件,把这个文件拷到Uclinux内核里面去,将w5500的miso、mosi、cs、clk与stm32的spi1的miso、mosi、cs、clk接口用杜邦线相连,用网线将w5500和电脑直连,此时stm32是客户端,电脑是服务器。


    这里写图片描述


    这里写图片描述

           最后的效果如下图,服务器与客户端成功进行tcp连接,打开用网络调试助手发送数据出去,stm32客户端的w5500应用程序是写接收到服务器的数据后,再打包发送到服务器,于是我们就可以看到在电脑网络调试助手上显示出接收到stm32客户端的数据,这样就实现服务器与客户端之间正常接收和发送数据,在Uclinux里也打印出所接收到的数据。

    这里写图片描述


    这里写图片描述


    这里写图片描述

    ————————————————————————————————————
           这是采用tcp的连接,用udp连接需要另外写程序设置(其实更简单),这样就通过w5500开出了一条沟通stm32到服务器的道理,由linux到服务器,但是这只是其中一种比较简易的应用,没投入到真正的应用之前也不敢说稳定较好。

           上头吩咐下来要再移植继电保护103协议到其中,远的话还要移植104协议、649协议等等,103协议已经看得差不多了,相关一些简易代码也已移植进去,其实无非就是在w5500的应用程序上添砖加瓦,但以后的工作要与服务器主站那边进行协议调试,根据协议传送数据……这还得继续努力,不断学习!最近也在看安卓方面的框架,学习java很感兴趣!不断充实自我技能提升,我也想拿高工资啊(手动捂脸)!

    展开全文
  • W5500的最新驱动

    2015-05-07 17:33:20
    官方提供了W5500的最新驱动库,下载地址如下: http://wizwiki.net/wiki/doku.php?id=products:w5500:driver
  • 本人在用的W5500驱动程序,稳定运行,已经在产品上批量使用,倾情共享; 单片机实现网络UDP模式,SO EASY!
  • 目录 ... W5500 W5500.c 使用方法 说明 需要调整的内容为W5500.h中关于IP地址、端口号、子网掩码、网关等参数 W5500 #ifndef _W5500_H_ #define _W5500_H_ /****************** Param...
  • W5200移植W5500驱动教程

    2019-07-13 18:17:11
    工程模板为我经常使用的一个w5500模板,可以在里面直接添加文件编程。1. 将driver文件夹中W5500文件夹和所有.c文件复制到工程/source文件夹下,并覆盖原来的文件,删除W5200文件夹 2. 将driver/include文件夹中...
  • STM32下W5500驱动

    2020-07-22 09:52:44
    stm32平台上运行的外w5500驱动,其实官网也有w5500驱动下载,附件可以运行的一个简单程序,w5500类型设置成了TCPclient,使用定时器检测是否有中断出现,并实现断开连接之后自动重连, 但不建议直接集成到项目,有写...
  • STM32F103驱动W5500网络程序STM32F103驱动W5500网络程序
  • 前段时间布置的任务是弄w5500驱动w5500本身硬件就具有tcp/ip协议,这样就省去了再把tcp协议栈移植到Uclinux的麻烦,而且我的存储空间一直是不够用的,所以选择w5500作为一个网卡来使用是再合适不过。 仔细看了...
  • 最近在移植W5500驱动,移植成功后。连到自己笔记本上(试了好几台笔记本),一直不识别网口。找了好多原因没找到,还以为是移植错了。 后来无意接到台式机上,尽然可以识别,而且还可以通信。 接到交换机上,可以...
  • 绘制的工程板电路及相关驱动程序五花八门。调试起来或多或少有些许问题。 所以想着写篇博文,给大家推荐下官网的链接,内有官方推荐电路及W5500相关例程。 W5500 以太网接口芯片权威设计指南网址链接——...
  • stm32模拟spi控制w5500

    2020-07-30 23:31:54
    stm32模拟spi控制w5500实现客户端模式,芯片spi借口有别的用途,通过软件模拟spi与w5500通信 stm32模拟spi控制w5500实现客户端模式,芯片spi借口有别的用途,通过软件模拟spi与w5500通信 stm32模拟spi控制w5500...
  • w5500客户端程序

    2020-07-30 23:32:14
    基于战舰开发板修改的W5500,把程序整合了一下,方便移植。
  • Linux内核驱动中将W5500 W5300和W5100集成到了一起,本人只用到了W5500。 问题描述 绿灯LinkLED和黄灯ACTLED交替闪烁,而正常状态应该为LinkLED常亮 ifconfig eth0 报错 经过观察W5500网卡在整个板子复位时...
  • W5500中文版手册

    2020-07-27 23:33:56
    W5500硬件网卡,硬件协议栈芯片(内含 MAC和 PHY)直接加网络接口,便可方便的实现单片机联网,所有的处理 TCP/IP 协议的工作都是通过这位 MCU 的“小秘书”——硬件协议栈芯片来完成。
  • STM32F103_W5500测试.rar

    2020-07-30 23:31:54
    本程序是Stm32F103平台下的W5500测试程序,程序包括DHCP, UDP, TCP,程序工程基于正点原子程序。 w5500官网链接(http://wizwiki.net/wiki/doku.php?id=products:w5500:driver)
1 2 3 4 5 ... 15
收藏数 291
精华内容 116
关键字:

w5500驱动