Hardware/STM32

[STM32F746G-DISCO] UDP echo server 테스트

rudals.kim 2024. 7. 21. 15:44
반응형
아래 테스트는 STM32CubeIDE 1.7.0/STM32Cube_FW_F7_V1.16.1를 사용하여 테스트 되었습니다.


STM32F746G-DISCO 보드용으로 제공되는 lwIP 예제가 적어서 STM32756G_EVAL에서 제공되는 예제를 살펴보니 다양한 lwIP 예제가 제공되고 있었고 이를 참고하여 UDP echo server 테스트를 해 보았습니다.
(참고 예제 : STM32Cube_FW_F7_V1.16.1/Projects/STM32756G_EVAL/Applications/LwIP/LwIP_UDP_Echo_Server)

새 프로젝트를 생성 후 DMA2D/ETH/FMC/FREERTOS/GPIO/LTDC/LWIP/NVIC/RCC/SYS/USART1을 설정하였습니다.

ETH 설정은 아래와 같이 기본값을 적용하였습니다.

lwIP의 대부분의 값은 기본값을 사용하였으며 테스트에 불필요한 HTTPD/SNMP/SNTP/SMTP/MDNS/TFTP 기능은 disable로 설정하였습니다.

FREERTOS는 CMSIS_V1 인터페이스의 기본 설정을 사용하였습니다.

FREERTOS의 기본 thread의 StartDefaultTask는 아래와 같이 적용하였습니다.

/* init code for LWIP */
//MX_LWIP_Init();
/* USER CODE BEGIN 5 */
BSP_Config();
tcpip_init(NULL, NULL);
Netif_Config();
udp_echoserver_init();
User_notification(&gnetif);

osThreadDef(DHCP, DHCP_thread, osPriorityBelowNormal, 0, configMINIMAL_STACK_SIZE * 2);
osThreadCreate (osThread(DHCP), &gnetif);

/* Infinite loop */
for(;;)
{
  osDelay(1);
}
/* USER CODE END 5 */


default thread에서 DHCP thread를 생성하는데 관련 부분은 이전과 마찬가지로 수동 IP 할당하는 부분은 삭제하였고, 동적 IP 할당인 DHCP 관련만 적용하였습니다.

void BSP_Config(void)
{
  BSP_LCD_Init();

  /* Initialize the LCD Layers */
  BSP_LCD_LayerDefaultInit(1, LCD_FB_START_ADDRESS);

  /* Set LCD Foreground Layer  */
  BSP_LCD_SelectLayer(1);

  BSP_LCD_SetFont(&LCD_DEFAULT_FONT);

  /* Initialize LCD Log module */
  LCD_LOG_Init();

  /* Show Header and Footer texts */
  LCD_LOG_SetHeader((uint8_t *)"UDP Echo Server Raw API");
  LCD_LOG_SetFooter((uint8_t *)"STM32F746G-DISCO board");

  LCD_UsrLog ("  State: Ethernet Initialization ...\n");
}

void Netif_Config(void)
{
  ip_addr_t ipaddr;
  ip_addr_t netmask;
  ip_addr_t gw;

  ip_addr_set_zero_ip4(&ipaddr);
  ip_addr_set_zero_ip4(&netmask);
  ip_addr_set_zero_ip4(&gw);

  netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);

  /*  Registers the default network interface. */
  netif_set_default(&gnetif);

  if (netif_is_link_up(&gnetif))
  {
    /* When the netif is fully configured this function must be called.*/
    netif_set_up(&gnetif);
  }
  else
  {
    /* When the netif link is down this function must be called */
    netif_set_down(&gnetif);
  }
}

void User_notification(struct netif *netif)
{
  if (netif_is_up(netif))
  {
    /* Update DHCP state machine */
    DHCP_state = DHCP_START;
  }
  else
  {
    /* Update DHCP state machine */
    DHCP_state = DHCP_LINK_DOWN;
    LCD_UsrLog ("The network cable is not connected \n");
  }
}

void DHCP_thread(void const * argument)
{
  struct netif *netif = (struct netif *) argument;
  ip_addr_t ipaddr;
  ip_addr_t netmask;
  ip_addr_t gw;
  struct dhcp *dhcp;
  uint8_t iptxt[20];

  for (;;)
  {
    switch (DHCP_state)
    {
    case DHCP_START:
      {
        ip_addr_set_zero_ip4(&netif->ip_addr);
        ip_addr_set_zero_ip4(&netif->netmask);
        ip_addr_set_zero_ip4(&netif->gw);
        dhcp_start(netif);
        DHCP_state = DHCP_WAIT_ADDRESS;
        LCD_UsrLog ("  State: Looking for DHCP server ...\n");
      }
      break;

    case DHCP_WAIT_ADDRESS:
      {
        if (dhcp_supplied_address(netif))
        {
          DHCP_state = DHCP_ADDRESS_ASSIGNED;

          sprintf((char *)iptxt, "%s", ip4addr_ntoa((const ip4_addr_t *)&netif->ip_addr));
          LCD_UsrLog ("IP address assigned by a DHCP server: %s\n", iptxt);
        }
        else
        {
          dhcp = (struct dhcp *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCP);

          /* DHCP timeout */
          if (dhcp->tries > MAX_DHCP_TRIES)
          {
            DHCP_state = DHCP_TIMEOUT;

            /* Stop DHCP */
            dhcp_stop(netif);

            /* Static address used */
            IP_ADDR4(&ipaddr, IP_ADDR0 ,IP_ADDR1 , IP_ADDR2 , IP_ADDR3 );
            IP_ADDR4(&netmask, NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
            IP_ADDR4(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
            netif_set_addr(netif, ip_2_ip4(&ipaddr), ip_2_ip4(&netmask), ip_2_ip4(&gw));

            sprintf((char *)iptxt, "%s", ip4addr_ntoa((const ip4_addr_t *)&netif->ip_addr));
            LCD_UsrLog ("DHCP Timeout !! \n");
            LCD_UsrLog ("Static IP address: %s\n", iptxt);
          }
        }
      }
      break;
  case DHCP_LINK_DOWN:
    {
      /* Stop DHCP */
      dhcp_stop(netif);
      DHCP_state = DHCP_OFF;
    }
    break;
    default: break;
    }

    /* wait 250 ms */
    osDelay(250);
  }
}


udp echo server 관련 소스는 udp_echoserver.c 파일을 그대로 가져다 사용하였습니다.

UDP echo 테스트를 하기 위해서는 echotool이라는 프로그램이 필요합니다. 아래 github에서 다운로드를 받습니다.

 

GitHub - PavelBansky/EchoTool: Command line echo server and client for Windows, designed according to RFC 862 specification for

Command line echo server and client for Windows, designed according to RFC 862 specification for Echo protocol. - PavelBansky/EchoTool

github.com

UDP echo server 예제의 기본적인 동작은 아래 그림과 같이 동작됩니다.

STM32F746G-DISCO에서 UDP echo server를 실행하여 메시지 수신 대기를 한 후 PC에서 echotool을 사용하여 UDP Client 모드에서 'Testing LwIP UDP echo server' 메시지를 Server인 STM32F746G-DISCO로 전송하면 Server단에서는 이 수신된 메세지를 다시 Client로 재전송을 하는 구조로 동작됩니다.

PC에서 'echotool 192.168.0.16 /p udp /r 7 /l 7 /n 3 /t 2 /d Testing LwIP UDP echo server' 명령어를 사용하여 Server로 메시지를 전송합니다. Statistics 로그를 보면 3회 메시지를 전송하여 3회 모두 정상적으로 수신되었습니다.

PC의 Client로부터 송신된 3회의 메시지는 STM32F746G-DISCO의 LCD_UsrLog로 정상적으로 3회 출력되어졌습니다.

UDP 프로토콜을 사용하여 메시지 echo 테스트가 정상적으로 동작됨을 확인해 보았습니다.

반응형