abner_ma 发表于 2023-2-27 19:13

基于STM32的IPv4/IPv6 网关设计

#申请原创#
    最近项目开发需求,需要设备支持IPV6协议,用过,W5500。发现WIZnet 推出新款:W6100模组, 是一款支持 IPv4/IPv6 双核的新一代全硬件以太网 TCP/IP 协议栈控制器。W6100 在 WIZnetTCP/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;
   tAD = (uint8_t)((AddrSel & 0x00FF0000) >> 16);
   tAD = (uint8_t)((AddrSel & 0x0000FF00) >> 8);
   tAD = (uint8_t)(AddrSel & 0x000000ff);
   tAD = wb;

   //WIZCHIP_CRITICAL_ENTER();
// WIZCHIP.CS._s_e_l_e_c_t_();
   IINCHIP_CSoff();
       
#if( (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_SPI_VDM_))
    tAD |= (_W6100_SPI_WRITE_ | _W6100_SPI_OP_);
    //IINCHIP_SpiSendData( 0xf0);
          IINCHIP_SpiSendData(tAD);// Address byte 1
    IINCHIP_SpiSendData(tAD );// Address byte 2
    IINCHIP_SpiSendData(tAD);// Address byte 1
    IINCHIP_SpiSendData(tAD );// Address byte 2
   

#elif ( (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_) )
   IINCHIP_BusSendData(IDM_AR0 ,tAD );
       IINCHIP_BusSendData(IDM_AR1 ,tAD );
       IINCHIP_BusSendData(IDM_BSR ,tAD );
       IINCHIP_BusSendData(IDM_DR, tAD);
#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_SPI1
#define MODE_BUS0


uint8_tWIZCHIP_READ(uint32_t AddrSel)
{
   uint8_t ret;
   uint8_t tAD;
   tAD = (uint8_t)((AddrSel & 0x00FF0000) >> 16);
   tAD = (uint8_t)((AddrSel & 0x0000FF00) >> 8);
   tAD = (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 |= (_W6100_SPI_READ_ | _W6100_SPI_OP_);
   IINCHIP_SpiSendData( tAD);       
   IINCHIP_SpiSendData( tAD);
   IINCHIP_SpiSendData( tAD);        // 控制段
   ret = IINCHIP_SpiSendData(0x00);      
#elif ( (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_) )
   IINCHIP_BusSendData(IDM_AR0 ,tAD);
       IINCHIP_BusSendData(IDM_AR1 ,tAD);
       IINCHIP_BusSendData(IDM_BSR ,tAD );
       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;
   tAD = (uint8_t)((AddrSel & 0x00FF0000) >> 16);
   tAD = (uint8_t)((AddrSel & 0x0000FF00) >> 8);
   tAD = (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 |= (_W6100_SPI_WRITE_ | _W6100_SPI_OP_);
   //        printf("write\r\n");                                                                                                                               
   if(len == 0) printf("Unexpected2 length 0\r\n");                        // 写入数据为空;len表示写入数据的长度
   IINCHIP_SpiSendData( tAD);                // 地址段,提供16位偏移地址(0000 0000 0000 0000)
   IINCHIP_SpiSendData( tAD);                // 控制段,共8位(0000 0000 高5位BSB位为00000表示通用寄存器)
   IINCHIP_SpiSendData( tAD);    // 控制段+4(0000 0100 RWB位置1表示写入,OM位为00表示SPI工作模式为VDM)
   for(idx = 0; idx < len; idx++)                                                // 数据段,写入数据值
   {
   IINCHIP_SpiSendData( pBuf);                                                                                        // MCU通过SPI发送数据
   }

#elif ( (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_) )
   IINCHIP_BusSendData(IDM_AR0 ,tAD);
       IINCHIP_BusSendData(IDM_AR1 ,tAD);
              IINCHIP_BusSendData(IDM_BSR ,tAD );
       for(idx = 0; idx < len; idx++)                // Write data in loop
   {
               IINCHIP_BusSendData(IDM_DR, pBuf);
       }
#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;
       uint16_t idx = 0;               
   tAD = (uint8_t)((AddrSel & 0x00FF0000) >> 16);
   tAD = (uint8_t)((AddrSel & 0x0000FF00) >> 8);
   tAD = (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 |= (_W6100_SPI_READ_ | _W6100_SPI_OP_);
   IINCHIP_SpiSendData(tAD);                // 地址段
IINCHIP_SpiSendData( tAD);                // 控制段
IINCHIP_SpiSendData( tAD);                    // 控制段
for(idx = 0; idx < len; idx++)                          // 数据段,读取数据值
{
    pBuf = IINCHIP_SpiSendData(0x00);                                                        // 将MCU通过SPI发送过来的数据存放在buf数组中
}
#elif ( (_WIZCHIP_IO_MODE_ == _WIZCHIP_IO_MODE_BUS_INDIR_) )
   IINCHIP_BusSendData(IDM_AR0 ,tAD);
       IINCHIP_BusSendData(IDM_AR1 ,tAD);
              IINCHIP_BusSendData(IDM_BSR ,tAD );
       for(idx = 0; idx < len; idx++)                // Write data in loop
   {
               pBuf =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);
}


/// @cond 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需要完成版程序可以跟我索取


页: [1]
查看完整版本: 基于STM32的IPv4/IPv6 网关设计