STM32F746G-DISCO 보드용으로 제공되는 lwIP 예제가 적어서 STM32756G_EVAL에서 제공되는 예제를 살펴보니 다양한 lwIP 예제가 제공되고 있었고 이를 참고하여 TCP & UDP echo server 테스트를 해 보았습니다.
(참고 예제 : STM32Cube_FW_F7_V1.16.1/Projects/STM32756G_EVAL/Applications/LwIP/LwIP_UDPTCP_Echo_Server_Netconn_RTOS)
새 프로젝트를 생성 후 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는 아래와 같이 적용하였습니다.
void StartDefaultTask(void const * argument)
{
/* init code for LWIP */
//MX_LWIP_Init();
/* USER CODE BEGIN 5 */
BSP_Config();
/* Create tcp_ip stack thread */
tcpip_init(NULL, NULL);
/* Initialize the LwIP stack */
Netif_Config();
/* Initialize tcp echo server */
tcpecho_init();
/* Initialize udp echo server */
udpecho_init();
/* Notify user about the network interface config */
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 *)"TCP UDP Server Netconn 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, ðernetif_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);
}
}
TCP/UDP echo server 관련 소스는 tcpecho.c 와 udpecho.c 파일을 그대로 가져다 사용하였습니다.
TCP/UDP echo 테스트를 하기 위해서는 echotool이라는 프로그램이 필요한데 아래 github에서 다운로드를 받습니다.
TCP/UDP echo server 예제의 기본적인 동작은 아래 그림과 같이 동작됩니다.
STM32F746G-DISCO에서 TCP/UDP echo server를 실행하여 메시지 수신 대기를 한 후 PC에서 echotool을 사용하여 TCP/UDP Client 모드에서 'Testing LwIP TCP/UDP echo server' 메시지를 Server인 STM32F746G-DISCO로 송신하면 Server단에서는 이 수신된 메세지는 다시 Client로 재전송을 하는 구조로 동작됩니다.
PC Client에서 아래 명령어를 사용하여 TCP/UDP 메시지를 Server로 전송합니다
TCP 명령어 : echotool IP_address /p tcp /r 7 /n 3 /t 2 /d Testing LwIP TCP echo server UDP 명령어 : echotool IP_address /p udp /r 7 /l 7 /n 3 /t 2 /d Testing LwIP UDP echo server |
Statistics를 보면 정상적으로 TCP/UDP 모두 총 송신 3회에 수신 3회가 된것을 확인 할 수 있습니다.
Client에서 TCP/UDP 명령어를 각 각 3회씩 전송시 Server에서는 아래와 같이 TCP 3회 및 UDP 3회의 수신 메시지를 확인 할 수 있습니다.
메시지는 아래 제공되는 netbuf API중 netbuf_data 함수를 참고하여 버퍼를 dump 받은 후 확인하였습니다.
TCP/UDP 프로토콜을 사용하여 메시지 echo 테스트가 정상적으로 동작됨을 확인해 보았습니다.
'Hardware > STM32' 카테고리의 다른 글
[STM32F746G-DISCO] HTTP server 테스트 (0) | 2024.07.22 |
---|---|
[STM32F746G-DISCO] UDP echo server 테스트 (0) | 2024.07.21 |
[STM32F746G-DISCO] UDP echo client 테스트 (0) | 2024.07.21 |
[STM32F746G-DISCO] TCP echo server 테스트 (0) | 2024.07.20 |
[STM32F746G-DISCO] TCP echo client 테스트 (0) | 2024.07.20 |
댓글