본문 바로가기
DSP, MCU/STM32 (ARM Cortex-M)

STM32 ] LwIP 사용 초기설정 후 핑테스트

by eteo 2022. 9. 24.

사용 보드 : STM32F429ZI

환경 :

STM32CubeIDE 1.10.1

STM32Cube FW_F4 V1.27.1

without RTOS

 

 

먼저 클락 설정

 

 

 

 

 

 

ETH 설정

 

 

RMII 방식을 선택해준다. 이는 스키매틱을 보면 Nucleo-144 보드에는 LAN8742 라는 PHY 칩이 내장되어 있는데 이미 RMII 회로로 구성되어 있기 때문이다.

 

Ethernet MAC 주소가 보이는데 앞의 3 byte는 생산자 코드이고 뒤의 3 byte는 시리얼 넘버이다.

 

 

 

디폴트로 내장된 PHY 칩을 사용할거기 때문에 Advanced Parameters 에도 건들 것이 없다.

 

 

다만 GPIO 핀 설정은 위의 스키매틱을 보면서 제대로 설정되었는지 확인해 줄 필요가 있다.

 

 

 

 

다음 Middleware에서 LwIP를 Enable 한다.

 

 

여기서 지금 당장은 건들 것이 없다. DHCP 를 사용하는 버전을 먼저 해볼거다. Platform Settings 에서 LAN8742 를 선택해주자.

 

 

 

코드 제네레이션을 하고 다음과 같이 추가한다.

 

//...
/* USER CODE BEGIN PV */
extern struct netif gnetif;
/* USER CODE END PV */
//...
int main(void)
{
  //...
  /* Initialize all configured peripherals */
  MX_LWIP_Init();	// MX로 자동생성되는 이 코드 안에서 필요한 설정을 한다.
  //...
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  ethernetif_input(&gnetif);
	  sys_check_timeouts();
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
//...

 

DHCP 를 enable 했으니까 동적 IP 가 할당되었을 텐데 한번 확인해보자

Expressions에 gnetif 구조체를 추가하고 ip_addr을 보면 주소값이 데시멀 포맷으론 201369792 헥사 포맷으로 0x0C00A8C0 이 나온다.

 

DHCP를 사용하는 경우 UART로 할당된 ip를 출력하는 코드를 init 함수 아래 배치 하면 유용할 것 같다.

 

 

암튼 IP 주소가 192.168.0.12 이다.

 

 

이 주소로 ping 을 날려보자

 

 

 

 

다음 DHCP를 사용하지 않고 고정IP를 쓰는 버전도 해보자.

아래와 같이 IP Address 셋팅을 하고 코드는 그대로 둔다.

 

수정한 고정  ip로 핑이 제대로 가는 것을 확인할 수 있다.

 

 

핑테스트가 성공하기 까지 어떤 과정을 거쳤을지 생각해보자

 

1. 192.168.0.200 이라는 ip 주소를 가진 놈에게 패킷을 보내려고 하는데 ip 주소만 알고 MAC 주소는 모른다. 실제 패킷을 들고 찾아가기 위해서는 논리주소인 ip 주소 말고 물리주소인 MAC 주소를 알아야 한다.

 

2. 일단 서브넷마스크(255.255.255.0)를 통해 동일 네트워크인지 확인한다. 내 PC ip 주소와 서브넷 마스크를 & 연산하고 목적지 ip 주소와 서브넷마스크를 &연산했을때 나오는 네트워크 주소가 192.168.0.0 으로 동일하다면 동일 네트워크에 있다고 판단할 수 있다.

 

3. 네트워크 내의 브로드 캐스트 ip (192.168.0.255, 보통 해당 네트워크의 맨 마지막 주소)의 MAC 주소(FF:FF:FF:FF:FF:FF)는 갖고 있으니 브로드 캐스트(1:다)로 해당 ip 에 맵핑되는 MAC 주소를 찾는 ARP (Address Resolution Protocol) 요청 패킷을 보낸다.

 

4. 네트워크 내 모든 호스트와 라우터는 ARP 요청 패킷을 수신하고 해당되는 수신자(192.168.0.200) 는 자신의 논리주소와 물리주소를 넣은 ARP 응답 패킷을 유니캐스트(1:1)로 전송한다.

 

5. 목적지의 MAC 주소를 알아냈다. 그리고 ARP 테이블에 ip 와 MAC 주소를 대응시켜 기록해둔다. 다음번엔 이 ARP 테이블을 확인해서 바로 해당 MAC 주소로 프레임을 전송할 수 있다.

 

 

만약 2번에서 다른 네트워크에 있다고 판단이 됐다면 게이트웨이(192.168.0.1, 공유기의 ip 주소)를 통해 바깥으로 나가 MAC 주소를 알아내야 한다.

 

 

참고로 커맨드 창에서 arp -a 를 치면 ARP table을 볼 수 있다.

STM32의 MAC 주소와 ip 주소가 맵핑된 정보가 보인다. 이 테이블은 유효시간이 있고 보통 10분이 지나면 동적 데이터는 사라지게 된다.

 

 

 

그다음 코드를 살펴보면

 

사실 while문 내의 저 두 문장 대신 lwip.c 파일 내에 있는 MX_LWIP_Process() 함수를 가져다 써도 된다.

 

/**
 * ----------------------------------------------------------------------
 * Function given to help user to continue LwIP Initialization
 * Up to user to complete or change this function ...
 * Up to user to call this function in main.c in while (1) of main(void)
 *-----------------------------------------------------------------------
 * Read a received packet from the Ethernet buffers
 * Send it to the lwIP stack for handling
 * Handle timeouts if LWIP_TIMERS is set and without RTOS
 * Handle the llink status if LWIP_NETIF_LINK_CALLBACK is set and without RTOS
 */
void MX_LWIP_Process(void)
{
/* USER CODE BEGIN 4_1 */
/* USER CODE END 4_1 */
  ethernetif_input(&gnetif);

/* USER CODE BEGIN 4_2 */
/* USER CODE END 4_2 */
  /* Handle timeouts */
  sys_check_timeouts();

  Ethernet_Link_Periodic_Handle(&gnetif);

/* USER CODE BEGIN 4_3 */
/* USER CODE END 4_3 */
}

 

 

 

이중 ethernetif_input(&gnetif);는 polling으로 수신된 패킷이 있는지 체크하는 역할이다. 

관련 글 : https://naudhizb.tistory.com/945

 

 

그리고 sys_check_timeouts();는 lwIP에 내부적으로 필요한 주기작업을 처리하기 위한 함수로 mainloop에서 주기호출되어야 한다.

 

다음 Ethernet_Link_Periodic_Handle(&gnetif); 는 이더넷이 링크된 상태인지 polling으로 체크하는 함수이다.

 

 

코드를 좀 추가해서 이더넷이 정상작동하는지 LED로 표시할 수도 있다.

 

 

 

참고.

이전 CubeIDE버전을 사용하고 있다면 오류가 날 수 있다. 오류가 나면 아래 파일의 해당부분을 주석처리 해줘야 제대로 작동한다.