[通信技术资料]基于STM32的IPv4/IPv6 网关设计

最近项目开发需求,需要设备支持IPV6协议,用过,W5500。发现WIZnet 推出新款:W6100模组, 是一款支持 IPv4/IPv6 双核的新一代全硬件以太网 TCP/IP 协议栈控制器。W6100 在 WIZnet  TCP/IP 协议栈 IPv4 的基础上增加了 IPv6,并且支持 TCP,UDP,IPv6,IPv4,ICMPv6,ICMPv4,IGMP,ARP 以及 PPPoE 等协议。同时其内部集成了 10/100M 以太网数据链路层(MAC)以及物理层(PHY),能够更加简单快速地实现嵌入式设备的联网功能。   IPv6三种转换技术当前,网站应用IPv6升级改造的技术路线主要有双栈、隧道和转换等三种技术。对嵌入式系统用单芯片解决。目前ESP32对IPV6支持。
     武汉、西安、沈阳、南京、重庆、杭州、贵阳·贵安、福州8个互联网骨干直联点全部完成了IPv6升级改造,支持互联网间IPv6流量交换。加上2018年完成的北京、上海、广州、郑州、成都等5个骨干网直联点,我国全部13个骨干网直联点全部完成了IPv6改造。我国IPv6地址拥有数量稳定增加,截至2020年1月,我国已申请了47851块(/32)IPv6地址,位居世界第二。IPv6活跃用户量大幅提升。截至2020年1月,我国IPv6活跃用户数达2.7亿,占互联网网民总数的31%,相比行动计划实施前,增长了近100倍。全国已有11.93亿LTE用户、1.99亿固定网络用户,合计13.92亿用户获得了IPv6地址。


   



W6100 内部架构图:

STM32 SPI驱动: WIZ_SPI_Init

 

#include "SPI.h"

#include "w6100_init.h"

void WIZ_SPI_Init(void)      //SPI 初始

{

        SPI_InitTypeDef   SPI_InitStructure;

        GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO , ENABLE);

 

        /* Configure SPIy pins: SCK, MISO and MOSI */

  GPIO_InitStructure.GPIO_Pin = WIZ_SCLK|  WIZ_MISO| WIZ_MOSI;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

        

        /*Init WIZ_SCS*/

  GPIO_InitStructure.GPIO_Pin =  WIZ_SCS; 

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_SetBits(GPIOA, WIZ_SCS);

                 

        /* SPI Config -------------------------------------------------------------*/

                 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

          SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

          SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

          SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;

          SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;

          SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

          SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;

          SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

          SPI_InitStructure.SPI_CRCPolynomial = 7;



          SPI_Init(SPI1, &SPI_InitStructure);

          SPI_Cmd(SPI1, ENABLE);

}



void WIZ_CS(uint8_t val)

{

        if (val == LOW) 

        {

                   GPIO_ResetBits(GPIOA, WIZ_SCS); 

        }

        else if (val == HIGH)

        {

                   GPIO_SetBits(GPIOA, WIZ_SCS); 

        }

}



uint8_t SPI1_SendByte(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);

          

          return SPI_I2S_ReceiveData(SPI1);

}





关键代码:


#include "w6100.h"

#include "SPI.h"

#include <stdio.h>

#include "w6100_init.h"



#define _WIZCHIP_SPI_VDM_OP_    0x00

#define _WIZCHIP_SPI_FDM_LEN1_  0x01

#define _WIZCHIP_SPI_FDM_LEN2_  0x02

#define _WIZCHIP_SPI_FDM_LEN4_  0x03

//

// If you want to use SPI FDM mode, Feel free contact to WIZnet. 

// http://forum.wiznet.io

//



#if _WIZCHIP_ == 6100







#define _W6100_SPI_OP_          _WIZCHIP_SPI_VDM_OP_



/***

*@brief: send data in BUS mode 

*@parame: addr: register address

*         data: value write to register

*@return: none

*****/

void IINCHIP_BusSendData(uint32_t addr,uint8_t data)

{

         *((volatile uint8_t*)addr) = data;



}

/***

*@brief: read data in BUS mode 

*@parame: addr: register address

*         data: value read from register

*@return: register value

*****/

uint8_t IINCHIP_BusReadData(uint32_t addr)

{

         return *((volatile uint8_t*)addr) ;



}



/***

*@brief:  pull down cs pin 

*@parame: none

*@return: none

*****/

void IINCHIP_CSoff(void)

{

  WIZ_CS(LOW);

}



/***

*@brief: pull up cs pin 

*@parame: none

*@return: none

*****/

void IINCHIP_CSon(void)

{

   WIZ_CS(HIGH);

}



/***

*@brief: send data in SPI mode 

*@parame: data: value write to register

*@return: none

*****/

uint8_t IINCHIP_SpiSendData(uint8_t dat)

{

   return(SPI1_SendByte(dat));

}





//

void WIZCHIP_WRITE(uint32_t AddrSel, uint8_t wb )

{

   uint8_t tAD[4];

   tAD[0] = (uint8_t)((AddrSel & 0x00FF0000) >> 16);

   tAD[1] = (uint8_t)((AddrSel & 0x0000FF00) >> 8);

   tAD[2] = (uint8_t)(AddrSel & 0x000000ff);

   tAD[3] = wb;



   //WIZCHIP_CRITICAL_ENTER();

  // WIZCHIP.CS._s_e_l_e_c_t_();

     IINCHIP_CSoff(); 

        

#if( (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_))

    tAD[2] |= (_W6100_SPI_WRITE_ | _W6100_SPI_OP_);

    //IINCHIP_SpiSendData( 0xf0);

          IINCHIP_SpiSendData(tAD[0]);// Address byte 1

    IINCHIP_SpiSendData(tAD[1] );// Address byte 2

    IINCHIP_SpiSendData(tAD[2]);// Address byte 1

    IINCHIP_SpiSendData(tAD[3] );// Address byte 2

    



#elif ( (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_) )

   IINCHIP_BusSendData(IDM_AR0 ,tAD[0] );

         IINCHIP_BusSendData(IDM_AR1 ,tAD[1] );

         IINCHIP_BusSendData(IDM_BSR ,tAD[2] );

         IINCHIP_BusSendData(IDM_DR, tAD[3]);

#else

   #error "Unknown _WIZCHIP_IO_MODE_ in W5100. !!!"

#endif

   IINCHIP_CSon(); 

  // WIZCHIP.CS._d_e_s_e_l_e_c_t_();

  // WIZCHIP_CRITICAL_EXIT();

}



#define MODE_SPI  1

#define MODE_BUS  0





uint8_t  WIZCHIP_READ(uint32_t AddrSel)

{

   uint8_t ret;

   uint8_t tAD[3];

   tAD[0] = (uint8_t)((AddrSel & 0x00FF0000) >> 16);

   tAD[1] = (uint8_t)((AddrSel & 0x0000FF00) >> 8);

   tAD[2] = (uint8_t)(AddrSel & 0x000000ff);



  // WIZCHIP_CRITICAL_ENTER();

  // WIZCHIP.CS._s_e_l_e_c_t_();

 IINCHIP_CSoff(); 

#if( (_WIZCHIP_IO_MODE_ ==  _WIZCHIP_IO_MODE_SPI_VDM_))

   tAD[2] |= (_W6100_SPI_READ_ | _W6100_SPI_OP_);

   IINCHIP_SpiSendData( tAD[0]);        

   IINCHIP_SpiSendData( tAD[1]);

   IINCHIP_SpiSendData( tAD[2]);        // 控制段

   ret = IINCHIP_SpiSendData(0x00);      

#elif ( (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_) )

   IINCHIP_BusSendData(IDM_AR0 ,tAD[0]);

         IINCHIP_BusSendData(IDM_AR1 ,tAD[1]);

         IINCHIP_BusSendData(IDM_BSR ,tAD[2] );

         ret = IINCHIP_BusReadData(IDM_DR);

#else

   #error "Unknown _WIZCHIP_IO_MODE_ in W6100. !!!"   

#endif



  // WIZCHIP.CS._d_e_s_e_l_e_c_t_();

  // WIZCHIP_CRITICAL_EXIT();

         IINCHIP_CSon(); 

   return ret;

}



void WIZCHIP_WRITE_BUF(uint32_t AddrSel, uint8_t* pBuf, datasize_t len)

{

         uint16_t idx = 0;                // idx定义为正在写入的第几个数

   uint8_t tAD[3];

   tAD[0] = (uint8_t)((AddrSel & 0x00FF0000) >> 16);

   tAD[1] = (uint8_t)((AddrSel & 0x0000FF00) >> 8);

   tAD[2] = (uint8_t)(AddrSel & 0x000000ff);



   IINCHIP_CSoff();  

   // WIZCHIP_CRITICAL_ENTER();

   //WIZCHIP.CS._s_e_l_e_c_t_();



#if((_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_))

   tAD[2] |= (_W6100_SPI_WRITE_ | _W6100_SPI_OP_);

   //        printf("write\r\n");                                                                                                                                

   if(len == 0) printf("Unexpected2 length 0\r\n");                        // 写入数据为空;len表示写入数据的长度

   IINCHIP_SpiSendData( tAD[0]);                // 地址段,提供16位偏移地址(0000 0000 0000 0000)

   IINCHIP_SpiSendData( tAD[1]);                // 控制段,共8位(0000 0000 高5位BSB位为00000表示通用寄存器)

   IINCHIP_SpiSendData( tAD[2]);    // 控制段+4(0000 0100 RWB位置1表示写入,OM位为00表示SPI工作模式为VDM)

   for(idx = 0; idx < len; idx++)                                                // 数据段,写入数据值

   {

     IINCHIP_SpiSendData( pBuf[idx]);                                                                                        // MCU通过SPI发送数据

   }



#elif ( (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_) )

   IINCHIP_BusSendData(IDM_AR0 ,tAD[0]);

         IINCHIP_BusSendData(IDM_AR1 ,tAD[1]);

                  IINCHIP_BusSendData(IDM_BSR ,tAD[2] );

         for(idx = 0; idx < len; idx++)                // Write data in loop

   {

                 IINCHIP_BusSendData(IDM_DR, pBuf[idx]);

         }

#else

   #error "Unknown _WIZCHIP_IO_MODE_ in W6100. !!!!"

#endif



  // WIZCHIP.CS._d_e_s_e_l_e_c_t_();

  // WIZCHIP_CRITICAL_EXIT();

        IINCHIP_CSon(); 

}



void WIZCHIP_READ_BUF (uint32_t AddrSel, uint8_t* pBuf, datasize_t len)

{

   uint8_t tAD[3];

         uint16_t idx = 0;                

   tAD[0] = (uint8_t)((AddrSel & 0x00FF0000) >> 16);

   tAD[1] = (uint8_t)((AddrSel & 0x0000FF00) >> 8);

   tAD[2] = (uint8_t)(AddrSel & 0x000000ff);



  // WIZCHIP_CRITICAL_ENTER();

  // WIZCHIP.CS._s_e_l_e_c_t_();

        IINCHIP_CSoff();        

if(len == 0)                                                                                                                                                                // len定义为读取数据的长度

  {        

   // printf("Unexpected2 length 0\r\n");                                                                // 读取数据长度为0

  }

#if((_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_))

   tAD[2] |= (_W6100_SPI_READ_ | _W6100_SPI_OP_);

   IINCHIP_SpiSendData(tAD[0]);                // 地址段

  IINCHIP_SpiSendData( tAD[1]);                // 控制段

  IINCHIP_SpiSendData( tAD[2]);                    // 控制段

  for(idx = 0; idx < len; idx++)                            // 数据段,读取数据值

  {

    pBuf[idx] = IINCHIP_SpiSendData(0x00);                                                        // 将MCU通过SPI发送过来的数据存放在buf数组中

  }

#elif ( (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_) )

   IINCHIP_BusSendData(IDM_AR0 ,tAD[0]);

         IINCHIP_BusSendData(IDM_AR1 ,tAD[1]);

                  IINCHIP_BusSendData(IDM_BSR ,tAD[2] );

         for(idx = 0; idx < len; idx++)                // Write data in loop

   {

                 pBuf[idx] =IINCHIP_BusReadData(IDM_DR);

         }

        

#else

   #error "Unknown _WIZCHIP_IO_MODE_ in W6100. !!!!"

#endif

         IINCHIP_CSon();  

}



datasize_t getSn_TX_FSR(uint8_t sn)

{

   datasize_t prev_val=-1,val=0;

   do

   {

      prev_val = val;

      val = WIZCHIP_READ(W6100_Sn_TX_FSR_(sn));

      val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(W6100_Sn_TX_FSR_(sn),1));

   }while (val != prev_val);

   return val;

}



datasize_t getSn_RX_RSR(uint8_t sn)

{

   datasize_t prev_val=-1,val=0;

   do

   {

      prev_val = val;

      val = WIZCHIP_READ(W6100_Sn_RX_RSR_(sn));

      val = (val << 8) + WIZCHIP_READ(WIZCHIP_OFFSET_INC(W6100_Sn_RX_RSR_(sn),1));

   }while (val != prev_val);

   return val;

}



void wiz_send_data(uint8_t sn, uint8_t *wizdata, datasize_t len)

{

   datasize_t ptr = 0;

   uint32_t addrsel = 0;

   ptr = getSn_TX_WR(sn);

   addrsel = ((uint32_t)ptr << 8) + WIZCHIP_TXBUF_BLOCK(sn);

   WIZCHIP_WRITE_BUF(addrsel,wizdata, len);

   ptr += len;

   setSn_TX_WR(sn,ptr);

}



void wiz_recv_data(uint8_t sn, uint8_t *wizdata, datasize_t len)

{

   datasize_t ptr = 0;

   uint32_t addrsel = 0;

   if(len == 0) return;

   ptr = getSn_RX_RD(sn);

   addrsel = ((uint32_t)ptr << 8) + WIZCHIP_RXBUF_BLOCK(sn);

   WIZCHIP_READ_BUF(addrsel, wizdata, len);

   ptr += len;

   setSn_RX_RD(sn,ptr);

}



void wiz_recv_ignore(uint8_t sn, datasize_t len)

{

   setSn_RX_RD(sn,getSn_RX_RD(sn)+len);

}





/// [url=home.php?mod=space&uid=1302964]@cond[/url] DOXY_APPLY_CODE

#if (_PHY_IO_MODE_ == _PHY_IO_MODE_MII_)

/// @endcond

void wiz_mdio_write(uint8_t phyregaddr, uint16_t var)

{

   setPHYRAR(phyregaddr);

   setPHYDIR(var);

   setPHYACR(PHYACR_WRITE);

   while(getPHYACR());  //wait for command complete

}



uint16_t wiz_mdio_read(uint8_t phyregaddr)

{

   setPHYRAR(phyregaddr);

   setPHYACR(PHYACR_READ);

   while(getPHYACR());  //wait for command complete

   return getPHYDOR();

}

/// @cond DOXY_APPLY_CODE

#endif

/// @endcond





#endif

 ---------------------
作者:abner_ma
链接:https://bbs.21ic.com/icview-3287028-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值