2. W5500으로 임베디드 이더넷 구현하기(드라이버 포팅)

W5500으로 이더넷 구현하기

목차

  1. 개발 환경 구축
    • LPCXpresso 설치
    • Flash Magic 설치
    • 신규 프로젝트 생성 방법
  2. W5500 드라이버 포팅
    • W5500-EVB W5500 Interface (SPI)
    • W5500 Driver Import
    • 초기화 함수 구현
      • W5500 초기화 Flow
      • MCU Interface 초기화 함수
      • Call Back 함수 구현
      • W5500 Chip 초기화 함수
      • Network 설정 함수
    • Main 함수 구현
    • Firmware 적용 및 테스트
  3. Echo-Server 구현
    • Echo-Server 구현

W5500 드라이버 포팅

W5500-EVB W5500 Interface (SPI)

W5500-EVB는 NXP LPC11E36 MCU를 사용하며, W5500과 SPI를 통하여 인터페이스 되어 있다. LPC11E36 MCU는 2개 채널의 SPI를 지원하는데 W5500과는 SPI0를 통해서 인터페이스 되어 있다. W5500-EVB에 대한 자세한 내용은 WIZnet wiki 사이트에서 참조하기 바란다.
http://wizwiki.net/wiki/doku.php?id=products:w5500:w5500_evb

아래의 그림은 W5500-EVB Schematic에서 W5500 인터페이스를 보여준다.

  • CS : PIO0_2 / SSEL0
  • SCLK : PIO0_6 / SCLK0
  • MISO : PIO0_8 / MISO0
  • MOSI : PIO0_9 / MOSI0
  • W5500_RST : PIO0_3

141029_w5500_interface1

141029_w5500_interface2

W5500 Driver Import

이전 강의록 “개발 환경 구축” 편을 참조하여 새로운 프로젝트를 생성한다.
1. W5500으로 이더넷 구현하기 (개발 환경 구축)
※ 프로젝트명을 W5500-EVB로 생성함

아래의 사이트에서 W5500 Driver 소스 코드를 다운로드 받는다.(파일명 : iolibrary_bsd_ethernet_v103.zip)
http://wizwiki.net/wiki/doku.php?id=products:w5500:driver

141029_wizwiki_hompage

소스 코드는 zip으로 압축된 형태로 배포된다. 압축을 풀면 Ethernet이라는 디렉토리가 생기며, 이 디렉토리 내에 W5500 Driver 소스 코드들이 존재한다. Ethernet 디렉토리를 새로 생성한 프로젝트의 src 디렉토리로 복사한다.

src 디렉토리

141029_porting1

LPCXpresso Project Explorer에서 생성한 프로젝트를 선택한 후 “F5″를 눌러 refresh를 하면, 복사한 Ethernet 디렉토리를 Project Explorer에서 확인 할 수 있다.

141029_porting2

복사한 Ethernet 디렉토리의 Include Path를 위해 다음 과정을 수행한다.
Project Explorer에서 W5500-EVB를 선택한 후, LPCXpresso 메뉴 Project->Properties를 클릭한다. 클릭하면 새로운 팝업 창이 뜨며, 오른쪽 메뉴의 C/C++ Build->Settings를 선택한다.

141029_porting3

Tool Settings 탭에서 MCU C Compiler -> Includes 항목을 선택한 후, 새로운 include 경로를 추가하기 위해 “+”로 표시된 아이콘을 클릭한다.

141029_porting4

“+”로 표시된 아이콘을 클릭하면 다음 창이 뜨며, Workspace…를 클릭한 후 W5500-EVB 프로젝트 내의 src 디렉토리를 선택하여 추가한다.

141029_porting5

141029_porting6

동일한 방법으로 Ethernet 디렉토리도 추가한다. 최종적으로 추가가 왼료되면 다음과 같이 나타난다.

141029_porting7

빌드하여 생성된 Firmware를 Flash Magic으로 보드에 적용하기 위해서는 Firmware가 Hex 파일 형태가 되어야 한다. Hex 파일 형태의 Firmware를 생성하기 위해서 다음의 과정을 수행한다.
Tool Settings 탭 오른쪽에 있는 Build steps 탭에서 Post-build steps -> Command 창의 Edit… 버튼을 누르면, 다음의 창이 뜨며 아래의 내용을 추가한다.(주의점 : #으로 시작하는 라인 위에 붙여넣기 해야 함)

arm-none-eabi-objcopy -O ihex "${BuildArtifactFileBaseName}.axf" "${BuildArtifactFileBaseName}.hex"

141029_porting8

추가한 후  “OK” 버튼을 누르면 다음 창이 뜨며, 여기서 방금 추가한 내용이 있는지 확인 후 “OK” 버튼을 눌러 다음 단계로 진행한다.

141029_porting9

표준 입출력 함수를 사용하기 위해 다음의 설정을 변경한다.
Tool Settings 탭에서 MCU Linker -> Managed Linker Script 항목을 선택한 후, Library 항목을 “Redlib(nohost)”로 변경한다.

141029_porting10

W5500 Driver 소스 Ethernet/W5500/w5500.h 파일에 다음 코드를 추가한다.
추가할 위치는 1176줄 “#define WIZCHIP_CRITICAL_EXIT() WIZCHIP.CRIS._exit()” 위에 추가한다.

#ifdef _exit
#undef _exit
#endif

141029_porting11

이 과정을 마친 후 빌드하면 정상적으로 빌드되는 것을 볼 수 있다.

141029_porting12

초기화 함수 구현

W5500 초기화 Flow

W5500을 사용하기 위해서는 다음의 초기화 과정이 필요하다.

  1. MCU Interface 초기화
    • SPI 관련 초기화
    • Reset Pin 관련 초기화
  2. Call back 함수 구현
    • Chip Select Functions
    • SPI Read/Write Functions
  3. W5500 Chip 초기화
    • H/W reset
    • Register Call Back Functions
    • Initializes to W5500 with SOCKET buffer size
  4. Network Information 초기화
MCU Interface 초기화 함수

MCU Inteface 초기화 함수에서는 SPI Inteface 관련 초기화 루틴과 Reset Pin 관련 초기화 루틴이 포함되어야 한다.

src 디렉토리에 spi_handler.h 파일을 생성한 후 Pin 관련 정보들을 정의한다.

#ifndef __SSP_H__
#define __SSP_H__

#define GPIO_SPI0_PORT      0
#define GPIO_W5500_RST_PORT 0

#define GPIO_SPI0_CS        2
#define GPIO_SPI0_CLK       6       
#define GPIO_SPI0_MISO      8
#define GPIO_SPI0_MOSI      9
#define GPIO_W5500_RST      3

void SPI_Init();

#endif

src 디렉토리에 spi_handler.c 파일을 생성한 후 다음의 초기화 루틴들을 구현한다.

헤더 파일 include

#include "board.h"
#include "spi_handler.h"

PIN Mux 설정 함수 구현

static void Init_SSP_PinMux(void)
{
    /* Configure SPI Pin */
    Chip_IOCON_PinMuxSet(LPC_IOCON, GPIO_SPI0_PORT, GPIO_SPI0_CLK, 
                    (IOCON_FUNC2 | IOCON_MODE_INACT | IOCON_DIGMODE_EN));
    Chip_IOCON_PinMuxSet(LPC_IOCON, GPIO_SPI0_PORT, GPIO_SPI0_MISO, 
                    (IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_DIGMODE_EN));
    Chip_IOCON_PinMuxSet(LPC_IOCON, GPIO_SPI0_PORT, GPIO_SPI0_MOSI, 
                    (IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_DIGMODE_EN));
    Chip_IOCON_PinMuxSet(LPC_IOCON, GPIO_SPI0_PORT, GPIO_SPI0_CS, 
                    (IOCON_FUNC0 | IOCON_MODE_PULLUP));
    Chip_GPIO_SetPinDIROutput(LPC_GPIO, GPIO_SPI0_PORT, GPIO_SPI0_CS);
    Chip_GPIO_SetPinState(LPC_GPIO, GPIO_SPI0_PORT, GPIO_SPI0_CS, true);

    /* Configure W5500 RESET Pin */
    Chip_GPIO_SetPinDIROutput(LPC_GPIO, GPIO_W5500_RST_PORT, GPIO_W5500_RST);
    Chip_GPIO_SetPinState(LPC_GPIO, GPIO_W5500_RST_PORT, GPIO_W5500_RST, true);
}

SPI 초기화 함수 (SPI Mode0 / SPI Clock 10MHz)

void SPI_Init()
{
    /* SSP initialization */
    Init_SSP_PinMux();
    Chip_SSP_Init(LPC_SSP0);

    Chip_SSP_SetFormat(LPC_SSP0, SSP_BITS_8, SSP_FRAMEFORMAT_SPI, SSP_CLOCK_MODE0);
    Chip_SSP_SetMaster(LPC_SSP0, true);
    Chip_SSP_SetBitRate(LPC_SSP0, 12000000);    // 12MHz
    Chip_SSP_Enable(LPC_SSP0);
}

W5500 Chip 초기화 함수

W5500 Chip 초기화 함수를 구현한다. 초기화 과정은 다음과 같다.

  • W5500 Chip Reset
  • Register SPI Call back Functions
  • W5500 Chip Initialization (Socket Buffer Size)

W5500 Chip Reset 방법은 Reset 핀을 High 상태에서 Low 상태로 바꾼 뒤 일정 시간 유지한 후, 다시 Reset 핀을 High 상태로 바꿔주면 된다.

src 디렉토리에 w5500_init.h 파일을 생성한 후, 다음을 정의 한다.

#ifndef __W5500_INIT_H__
#define __W5500_INIT_H__

void delay_cnt(volatile unsigned int nCount);
void display_net_info();
void Net_Conf();
void W5500_Init();

#endif

src 디렉토리에 w5500_init.c 파일을 생성한 후, 칩 초기화 루틴을 구현한다.

헤더 파일 include

#include <stdio.h>
#include "board.h"
#include "spi_handler.h"
#include "wizchip_conf.h"
#include "socket.h"

SPI Call back function

/* W5500 Call Back Functions */
static void  wizchip_select(void)
{
    Chip_GPIO_SetPinState(LPC_GPIO, GPIO_SPI0_PORT, GPIO_SPI0_CS, false);  // SSEL(CS)
}

static void  wizchip_deselect(void)
{
    Chip_GPIO_SetPinState(LPC_GPIO, GPIO_SPI0_PORT, GPIO_SPI0_CS, true);   // SSEL(CS)
}

static uint8_t wizchip_read()
{
    uint8_t rb;
    Chip_SSP_ReadFrames_Blocking(LPC_SSP0, &rb, 1);
    return rb;
}

static void  wizchip_write(uint8_t wb)
{
    Chip_SSP_WriteFrames_Blocking(LPC_SSP0, &wb, 1);
}

Delay 함수

void delay_cnt(volatile unsigned int nCount)
{
    for(; nCount!= 0;nCount--);
}

W5500 Chip 초기화 함수

void W5500_Init()
{
    uint8_t memsize[2][8] = { { 2, 2, 2, 2, 2, 2, 2, 2 }, { 2, 2, 2, 2, 2, 2, 2, 2 } };

    /* W5500 Chip Reset */
    Chip_GPIO_SetPinState(LPC_GPIO, GPIO_W5500_RST_PORT, GPIO_W5500_RST, false);
    delay_cnt(5000);
    Chip_GPIO_SetPinState(LPC_GPIO, GPIO_W5500_RST_PORT, GPIO_W5500_RST, true);
    delay_cnt(10000);

    /* Register Call back function */
    reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);
    reg_wizchip_spi_cbfunc(wizchip_read, wizchip_write);

    /* W5500 Chip Initialization */
    if (ctlwizchip(CW_INIT_WIZCHIP, (void*) memsize) == -1) {
        printf("WIZCHIP Initialized fail.\r\n");
        while (1);
    }  
}

Network 설정 함수

Network 정보들을 설정하기 위한 함수이다. 설정하는 정보들은 다음과 같다.

  • mac address
  • ip address
  • gateway
  • subnet mask
  • dns server
void display_net_info()
{
    wiz_NetInfo gWIZNETINFO;

    ctlnetwork(CN_GET_NETINFO, (void*) &gWIZNETINFO);
    printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", gWIZNETINFO.mac[0], gWIZNETINFO.mac[1], gWIZNETINFO.mac[2], gWIZNETINFO.mac[3], gWIZNETINFO.mac[4], gWIZNETINFO.mac[5]);
    printf("IP: %d.%d.%d.%d\r\n", gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3]);
    printf("GW: %d.%d.%d.%d\r\n", gWIZNETINFO.gw[0], gWIZNETINFO.gw[1], gWIZNETINFO.gw[2], gWIZNETINFO.gw[3]);
    printf("SN: %d.%d.%d.%d\r\n", gWIZNETINFO.sn[0], gWIZNETINFO.sn[1], gWIZNETINFO.sn[2], gWIZNETINFO.sn[3]);
    printf("DNS: %d.%d.%d.%d\r\n", gWIZNETINFO.dns[0], gWIZNETINFO.dns[1], gWIZNETINFO.dns[2], gWIZNETINFO.dns[3]);
}

void Net_Conf()
{
    wiz_NetInfo gWIZNETINFO = {
        { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 },    // Mac address
        { 192, 168, 0, 100 },                       // IP address
        { 255, 255, 255, 0},                        // Subnet mask
        { 192, 168, 0, 1},                          // Gateway        
        { 8, 8, 8, 8},                              // DNS Server
    };

    ctlnetwork(CN_SET_NETINFO, (void*) &gWIZNETINFO);

    display_net_info();
}

Main 함수 구현

W5500-EVB.c 파일에 헤더 파일 include 루틴을 추가한다.

#include "spi_handler.h"
#include "w5500_init.h"
#include "board.h"

W5500 Socket Interface를 사용하기 위해 socket.h를 include 한다.

#include "socket.h"

그 외 매크로와 상수를 선언한다.

#define SOCK_TCPS0       0
#define DATA_BUF_SIZE   2048
uint8_t gDATABUF[DATA_BUF_SIZE];

W5500-EVB.c 파일에 다음과 같이 구현한다.

int32_t loopback_tcps(uint8_t sn, uint8_t* buf, uint16_t port)
{
    return 1;
}

int main(void) { 

int ret = 0;

#if defined (__USE_LPCOPEN)
#if !defined(NO_BOARD_LIB)
    // Read clock settings and update SystemCoreClock variable
    SystemCoreClockUpdate();
    // Set up and initialize all required blocks and
    // functions related to the board hardware
    Board_Init();
    // Set the LED to the state of "On"
    Board_LED_Set(0, true);
#endif
#endif
    SPI_Init();
    W5500_Init();
    Net_Conf();

    while(1) {
             if((ret = loopback_tcps(SOCK_TCPS0, gDATABUF, 5000)) < 0) {
             printf("SOCKET ERROR : %ld\r\n", ret);
 }
    }   
    return 0;
}

Firmware 적용 및 테스트

※ W5500-EVB 연결 후 RS232 Driver를 설치해야 Serial 기능을 사용할 수 있다. RS232 Driver는 다음 링크에서 다운받을 수 있다.
다운로드(CDM v2.12.00 WHQL Certified.exe)

먼저 W5500-EVB를 ISP 모드로 동작시키기 위해서 ISP 버튼을 누른 상태에서 Reset 버튼을 누른다.

141029_w5500-evb_isp

Flash Magic 프로그램을 실행시킨다.
먼저 Step1 설정을 진행한다. Chip은 “LPC11E36/501″을 선택하며, 시리얼 설정은 각자 자신의 환경에 맞게 설정한다.

(COM port 는 장치관리자 메뉴로 들어가 확인한다. 실행창에 devmgmt.msc 를 입력하면 바로 열린다.)

141029_firm_test1

Step2에 “Erase all Flash+Code Rd Prot” 부분을 체크한다.

141029_firm_test2

Step3에 앞의 과정에서 생성한 Firmware Hex 파일을 지정한다. Firmware 파일은 프로젝트 내의 Debug 디렉토리 내에 존재한다.

141029_firm_test3

Start 버튼을 누르면 Firmware 이미지가 보드에 적용된다.

141029_firm_test4

시리얼 터미널 프로그램을 실행시킨 후, 보드 Reset 버튼을 누르면 다음과 같은 Network 설정 메시지들을 볼 수 있다. 동일 네트워크 상에서 보드에 설정된 “192.168.0.100”으로 ping을 보내면 정상 동작하는 것을 볼 수 있을 것이다.

141029_firm_test5

141029_firm_test6

소스 파일 : 다운로드
프로젝트 파일 : 다운로드

이전 : 1. W5500으로 임베디드 이더넷 구현하기(개발 환경 구축)

다음 : 3. W5500으로 이더넷 구현하기 (ECHO SERVER)

One thought on “2. W5500으로 임베디드 이더넷 구현하기(드라이버 포팅)

Leave a comment