发新帖本帖赏金 20.00元(功能说明)我要提问
返回列表
[通信技术资料]

基于STM32的IPv4/IPv6 网关设计

[复制链接]
347|0
手机看帖
扫描二维码
随时随地手机跟帖
abner_ma|  楼主 | 2023-2-27 19:13 | 显示全部楼层 |阅读模式
#申请原创#
    最近项目开发需求,需要设备支持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地址。


   1.jpg

2.jpg

W6100 内部架构图:
3.jpg
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
需要完成版程序可以跟我索取


使用特权

评论回复

打赏榜单

21ic小管家 打赏了 20.00 元 2023-03-13
理由:签约作者奖励

相关帖子

发新帖 本帖赏金 20.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:项目经理
简介:资深嵌入式开发工程师

59

主题

114

帖子

2

粉丝