W5500模块使用记录

一、模块介绍

W5500是一款以太网转SPI通信的芯片,芯片内部自带8个SOCKT通信,配置完成后可实现快速配置后可实现接入网络操作。下面是芯片厂家官网链接。

W5500官方网站_物联网芯片_以太网芯片_网络通信协议,轻松搞定嵌入式以太网!

二、芯片配置

1. SPI配置

根据数据手册,W5500支持SPI的模式0和模式3,数据高位在前,低位在后。

在STM32CubeMx上的配置如下所示,使能DMA的接收和发送:

生成的初始化代码

static void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */
}

/**
 * Enable DMA controller clock
 */
static void MX_DMA_Init(void)
{

  /* DMA controller clock enable */
  __HAL_RCC_DMA2_CLK_ENABLE();

  /* DMA interrupt init */
  /* DMA2_Stream0_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
  /* DMA2_Stream3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
}

/**
* @brief SPI MSP Initialization
* This function configures the hardware resources used in this example
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hspi->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspInit 0 */

  /* USER CODE END SPI1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PB3     ------> SPI1_SCK
    PB4     ------> SPI1_MISO
    PB5     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* SPI1 DMA Init */
    /* SPI1_RX Init */
    hdma_spi1_rx.Instance = DMA2_Stream0;
    hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
    hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_rx.Init.Mode = DMA_NORMAL;
    hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);

    /* SPI1_TX Init */
    hdma_spi1_tx.Instance = DMA2_Stream3;
    hdma_spi1_tx.Init.Channel = DMA_CHANNEL_3;
    hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_tx.Init.Mode = DMA_NORMAL;
    hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(hspi,hdmatx,hdma_spi1_tx);

    /* SPI1 interrupt Init */
    HAL_NVIC_SetPriority(SPI1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(SPI1_IRQn);
  /* USER CODE BEGIN SPI1_MspInit 1 */

  /* USER CODE END SPI1_MspInit 1 */
  }

}

2. W5500模块配置

可以通过w5500_network_info_show函数确定W5500的通信是否正常。

以太网的配置MAC地址第一个字节必须是偶数,否则会有出现Ping不通的问题。

    reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit);  // 注册临界区函数

    reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect); // 注册SPI片选信号函数

    reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte);   // 注册读写函数

    reg_wizchip_spiburst_cbfunc(SPI_BusRead, SPI_BusWrite);

这四个注册函数

reg_wizchip_spi_cbfunc是单个字节SPI读写的配置。

reg_wizchip_spiburst_cbfunc是多个字节SPI的读写配置。(可使用DMA的方式发送和接收)

void W5500_Reset(void)
{
    W5500_RS_RESET;
    HAL_Delay(50);
    W5500_RS_SET;
    HAL_Delay(50);
}

/**
 * @brief   set phy config if autonego is disable
 * @param   none
 * @return  none
 */
static void w5500_phy_init(void)
{
#ifdef USE_AUTONEGO
    // no thing to do
#else
    wiz_PhyConf conf;

    conf.by = PHY_CONFBY_SW;
    conf.mode = PHY_MODE_MANUAL;
    conf.speed = PHY_SPEED_100;
    conf.duplex = PHY_DUPLEX_FULL;

    wizphy_setphyconf(&conf);
#endif
}

/**
 * @brief   initializes the network infomation
 * @param   none
 * @return  none
 */
static void w5500_network_info_init(void)
{
    wiz_NetInfo info;

    uint8_t mac[6] = DEFAULT_MAC_ADDR;
    uint8_t ip[4] = DEFAULT_IP_ADDR;
    uint8_t sn[4] = DEFAULT_SUB_MASK;
    uint8_t gw[4] = DEFAULT_GW_ADDR;
    uint8_t dns[4] = DEFAULT_DNS_ADDR;

    memcpy(info.mac, mac, 6);
    memcpy(info.ip, ip, 4);
    memcpy(info.sn, sn, 4);
    memcpy(info.gw, gw, 4);
    memcpy(info.dns, dns, 4);

#ifndef USE_DHCP
    info.dhcp = NETINFO_DHCP;
#else
    info.dhcp = NETINFO_STATIC;
#endif

    wizchip_setnetinfo(&info);
}

/**
 * @brief   read and show the network infomation
 * @param   none
 * @return  none
 */
void w5500_network_info_show(void)
{
    wizchip_getnetinfo(&Showinfo);
}





/**
 * @brief   w5500 init
 * @param   none
 * @return  errcode
 * @retval  0   success
 * @retval  -1  chip init fail
 */
int W5500_init(void)
{
    /* W5500 hard reset */
    W5500_Reset();

    /* Register spi driver function */
    reg_wizchip_cris_cbfunc(SPI_CrisEnter, SPI_CrisExit);  // 注册临界区函数
    reg_wizchip_cs_cbfunc(SPI_CS_Select, SPI_CS_Deselect); // 注册SPI片选信号函数
    reg_wizchip_spi_cbfunc(SPI_ReadByte, SPI_WriteByte);   // 注册读写函数
    reg_wizchip_spiburst_cbfunc(SPI_BusRead, SPI_BusWrite);

    //W5500有16K的接收BUF和16K的发送BUF,填NULL就是默认每个Socket 2K    
    wizchip_init(NULL, NULL);  
    /* phy init */
    w5500_phy_init();

// /* network infomation init */
    w5500_network_info_init();

// /* show network infomation */
    w5500_network_info_show();

    reg_dhcp_cbfunc(NULL,NULL,NULL);  //注册DHCP回调函数
    
    return 0;
}

SPI的驱动函数 

extern SPI_HandleTypeDef hspi1;

uint8_t SPI_ReadByte(void)
{
  uint8_t value;

  if (HAL_SPI_Receive_DMA(&hspi1, &value, 1) != HAL_OK)
  {
    value = 0;
  }
  while(hspi1.State !=HAL_SPI_STATE_READY);
  return value;
}

void SPI_WriteByte(uint8_t byte)
{
    HAL_SPI_Transmit_DMA(&hspi1, &byte, 1);
    while(hspi1.State !=HAL_SPI_STATE_READY);
}

void SPI_BusRead(uint8_t *pBuf, uint16_t len)
{
  if (!pBuf)
  {
    return;
  }
  HAL_SPI_Receive_DMA(&hspi1, pBuf, len);
  while(hspi1.State !=HAL_SPI_STATE_READY);
}

void SPI_BusWrite(uint8_t *pBuf, uint16_t len)
{
  uint8_t ret = 0;
  if (!pBuf)
  {
    return;
  }
  ret = HAL_SPI_Transmit_DMA(&hspi1, pBuf, len);
  while(hspi1.State !=HAL_SPI_STATE_READY);
}


/**
  * @brief  进入临界区
  * @retval None
  */
void SPI_CrisEnter(void)
{
	//__set_PRIMASK(1);
}
/**
  * @brief  退出临界区
  * @retval None
  */
void SPI_CrisExit(void)
{
	//__set_PRIMASK(0);
}

/**
  * @brief  片选信号输出低电平
  * @retval None
  */
void SPI_CS_Select(void)
{
    HAL_GPIO_WritePin(SPI1_CS_GPIO_Port,SPI1_CS_Pin,GPIO_PIN_RESET);
}
/**
  * @brief  片选信号输出高电平
  * @retval None
  */
void SPI_CS_Deselect(void)
{
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port,SPI1_CS_Pin,GPIO_PIN_SET);
}



3. W5500执行任务

两路SOCKT,执行ModbusTCP主机

static int8_t mbTCPRecv(uint8_t sockt, uint8_t *pucMBTCPFrame, uint16_t *usTCPLength)
{
    uint16_t len;
    uint16_t usTCPBufPos;
    
    if(sockt > 7) return 0;

    
    len = getSn_RX_RSR(sockt);
    if (len > 0)
    {
        usTCPBufPos = recv(sockt, pucMBTCPFrame, len);
        *usTCPLength = usTCPBufPos;
        return 1;
    }
    else
    {
        return 0;
    }
}

static int8_t mbTCPSend(uint8_t sockt, uint8_t *pucMBTCPFrame, uint16_t usTCPLength)
{
    int32_t retVaule;
    if (sockt > 7)
        return 0;
    // 发送数据
    retVaule = send(sockt, pucMBTCPFrame, usTCPLength);
    if (retVaule > 0)
    {
        return 1;
    }
    else
    {
        return (int8_t)retVaule;
    }
}

void StartW5500Task(void const *argument)
{
    uint8_t state = 0;
    uint16_t len = 0;
    for (;;)
    {
              
        for (uint8_t socket_i = 0; socket_i < 2; socket_i++)
        {
            LED_GREEN_Togg;
            state = getSn_SR(socket_i);
            switch (state)
            {
            case SOCK_SYNSENT:
                break;
            case SOCK_INIT:
                listen(socket_i);
                break;
            case SOCK_LISTEN:
                break;
            case SOCK_ESTABLISHED:
                if (getSn_IR(socket_i) & Sn_IR_CON)
                {
                    setSn_IR(socket_i, Sn_IR_CON);
                }
                if (getSn_RX_RSR(socket_i))
                {
                    mbTCPRecv(socket_i, gDATABUF, &len);
                    memcpy(stModbusTCP.bModbusRTU_RxBuf, gDATABUF, len <=     MODBUS_TCP_RX_LEN ? len : 0);
                    Modbus_Parser(&stModbusTCP);
                    mbTCPSend(socket_i, stModbusTCP.bModbusRTU_TxBuf, stModbusTCP.bModbusRTU_TxLen);
                }
                break;
            case SOCK_CLOSE_WAIT:
                disconnect(socket_i);
                break;
            case SOCK_CLOSED:
            case SOCK_FIN_WAIT:
                close(socket_i);
                socket(socket_i, Sn_MR_TCP, SOCK_PORT, Sn_MR_ND); // Sn_MR_ND
                break;
            default:
                break;
            }
            osDelay(25);
        }
    

 
    }
}

4. W5500的DHCP获取IP地址

官方历程:从路由器获取动态IP地址_DHCP

 reg_dhcp_cbfunc(NULL,NULL,NULL);  //注册DHCP回调函数 

 DHCP_time_handler();  函数是DHCP驱动的时间戳,DHCP获取超时会使用到,当前为1S

/**
 * @brief 触发单次的DHCP,并获取IP地址
 *        获取失败后,应该触发W5500静态IP地址配置
 * @param[in] Showinfo  Comment
 * @return 0:获取失败 1:获取成功
 */
uint8_t DHCP_Get_IP(wiz_NetInfo *Showinfo)
{
    uint8_t ret = 0;
    uint8_t my_dhcp_retry = 0;
    uint8_t dhcp_time = 0;
    while (1)
    {
        switch (DHCP_run())
        {
        case DHCP_IP_LEASED:
            //
            // TO DO YOUR NETWORK APPs.
            // 获取IP地址并给出
            wizchip_getnetinfo(Showinfo);
            return 1;
            break;
        case DHCP_FAILED:
        case DHCP_STOPPED:
            my_dhcp_retry++;
            if (my_dhcp_retry >= 2) // 尝试2次停止DCHP
            {
                my_dhcp_retry = 0;
                DHCP_stop(); // if restart, recall DHCP_init()
                // network_init(); // apply the default static network and print out netinfo to serial
                return 0;
            }
            break;
        default:
            break;
        }
        if(dhcp_time++ > 10)
        {
            dhcp_time = 0;
            DHCP_time_handler();  //DHCP计时器
        }
        osDelay(100);
    }
}

DHCP_init(SOCK_DHCP,gDATABUF);   //按键触发后需要重新初始化
if(DHCP_Get_IP(&Showinfo) == 0)  //DHCP获取失败
{
    w5500_network_info_init();  //重新设置W5500IP地址
    w5500_network_info_show();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值