STM32 MCU 보드에서 W5500 사용하기 (2부)

목차

  1. 개발 환경 구축 (In Linux)
    • Build Tools 설치
    • ARM Tool Chain 설치
    • JAVA SE 설치
    • Eclipse 설치
    • GNU ARM Eclipse Plug-in 설치
    • stm32flash utility 설치
  2. STM32 빈 프로젝트 생성하기
  3. W5500 사용하기
    • 개발 보드 소개
    • W5500 인터페이스 구성 소개
    • W5500 Driver 포팅 하기

W5500 사용하기

개발 보드 소개

W5500-EVB (WIZnet HK)

w5500-evb

Board Specification

w5500-evb_spec

W5500 Interface 구성

w5500_interface1

w5500_interface2

  • Chip Select : GPIO PortB 12
  • SCLK : GPIO PortB 13
  • MISO : GPIO PortB 14
  • MOSI : GPIO PortB 15
  • Reset : GPIO PortB 9

W5500 Driver 포팅 하기

2번 과정을 참조하여 STM32 관련 새로운 프로젝트를 생성한다.
※ 이 예에서는 프로젝트 명을 w5500_project로 생성하였으며, eclipse workspace 위치는 사용자 홈 디렉토리 최상위에 workspace라는 디렉토리를 생성하여 지정하였다.( 프로젝트 디렉토리 위치 : ~/workspace/w5500_project )

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

wizwiki_hompage

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

$ unzip iolibrary_bsd_ethernet_v103.zip
$ mv Ethernet ~/workspace/w5500_project/src

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

porting2

Project Explorer에서 w5500_project를 선택한 후, Eclipse 메뉴 Project -> Properties 를 클릭한다. 클릭 하면 새로운 팝업 창이 뜨며, 오른쪽 메뉴의 C/C++ Build -> Settings를 선택한다.

porting3

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

porting4

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

porting5

porting6

최종적으로 추가가 완료되면 다음과 같이 나타난다.

porting7

Tool Setting 탭에서 Cross ARM GNU Create Flash Image -> General 를 선택한 후, Output file format을 “RAW binary”로 변경한 후, OK 버튼을 눌러 설정을 마무리 한다.

porting8

Eclipse 메뉴의 Project -> Build Project를 눌러 프로젝트를 빌드하면, 정상적으로 빌드 과정이 이루어 지는 것을 볼 수 있다.

W5500 Chip은 SPI Interface를 통해 MCU와 연결되며, W5500 Driver가 정상적으로 동작하기 위해서는 SPI 관련 인터페이스 함수들을 구현하여, Call back 함수로 등록해야 한다. Call back으로 등록해야 될 함수들은 다음과 같다.

  • void (* _select)(void) : SPI Chip Select 활성화 함수
  • void (* _deselect)(void) : SPI Chip Select 비활성화 함수
  • uint8_t (* _read_byte)(void) : SPI Read byte 함수
  • void (* _write_byte)(uint8_t wb) : SPI Write byte 함수

위의 SPI Interface 관련 함수들을 Call back 함수로 등록해 주는 함수는 다음과 같다.

  • void reg_wizchip_cs_cbfunc(void (* cs_sel)(void), void (* cs_desel)(void)) : SPI Chip Select Call back 함수를 등록하기 위한 함수
  • void reg_wizchip_spi_cbfunc(uint8_t (* spi_rb)(void), void (* spi_wb)(uint8_t wb)) : SPI Read/Write Call back 함수를 등록하기 위한 함수

※ 포팅 과정을 간략하게 소개한다. 전체 소스 코드는 따로 첨부함.
먼저 STM32 MCU에서 W5500을 사용하기 위한 하드웨어 Pin 정보들을 정의 하기 위해 src 디렉토리 내에 mcu_handler.h 파일을 생성하여, 하드웨어 Pin 정보들을 정의 한다.

#ifndef __MCU_HANDLER_H__
#define __MCU_HANDLER_H__

#define W5500_SPI                       SPI2
#define W5500_SPI_CLK                   RCC_APB1Periph_SPI2

#define W5500_SPI_SCK_PIN               GPIO_Pin_13 
#define W5500_SPI_SCK_GPIO_PORT         GPIOB
#define W5500_SPI_SCK_GPIO_CLK          RCC_APB2Periph_GPIOB

#define W5500_SPI_MISO_PIN              GPIO_Pin_14
#define W5500_SPI_MISO_GPIO_PORT        GPIOB
#define W5500_SPI_MISO_GPIO_CLK         RCC_APB2Periph_GPIOB

#define W5500_SPI_MOSI_PIN              GPIO_Pin_15
#define W5500_SPI_MOSI_GPIO_PORT        GPIOB
#define W5500_SPI_MOSI_GPIO_CLK         RCC_APB2Periph_GPIOB

#define W5500_CS_PIN                    GPIO_Pin_12
#define W5500_CS_GPIO_PORT              GPIOB
#define W5500_CS_GPIO_CLK               RCC_APB2Periph_GPIOB

#define W5500_RESET_PIN                 GPIO_Pin_9
#define W5500_CS_GPIO_PORT              GPIOB
#define W5500_CS_GPIO_CLK               RCC_APB2Periph_GPIOB

#define USART1_TX                       GPIO_Pin_9  
#define USART1_TX_GPIO_PORT             GPIOA
#define USART1_TX_GPIO_CLK              RCC_APB2Periph_GPIOA

#define USART1_RX                       GPIO_Pin_10
#define USART1_RX_GPIO_PORT             GPIOA
#define USART1_RX_GPIO_CLK              RCC_APB2Periph_GPIOA

#define USART1_CTS                      GPIO_Pin_11
#define USART1_CTS_GPIO_PORT            GPIOA
#define USART1_CTS_GPIO_CLK             RCC_APB2Periph_GPIOA

#define USART1_RTS                      GPIO_Pin_12
#define USART1_RTS_GPIO_PORT            GPIOA
#define USART1_RTS_GPIO_CLK             RCC_APB2Periph_GPIOA

#endif

STM32 MCU 하드웨어 초기화를 위해 src 디렉토리 내에 mcu_handler.c 파일을 생성하여 초기화 코드를 작성한다.
사용할 H/W의 RCC Clock을 설정 함수

void RCC_Configuration(void)
{
    /* SPI2 Clock Enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

    /* GPIOA, GPIOB, UART1 Clock Enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |    RCC_APB2Periph_USART1, ENABLE);
}

W5500 SPI Interface를 위한 SPI를 초기화 함수

void W5500_SPI_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef  SPI_InitStructure;

    /*!< Configure W5500_SPI pins: SCK */
    GPIO_InitStructure.GPIO_Pin = W5500_SPI_SCK_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(W5500_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);

    /*!< Configure W5500_SPI pins: MOSI */
    GPIO_InitStructure.GPIO_Pin = W5500_SPI_MOSI_PIN;
    GPIO_Init(W5500_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);

    /*!< Configure W5500_SPI pins: MISO */
    GPIO_InitStructure.GPIO_Pin = W5500_SPI_MISO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(W5500_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);

    /*!< Configure W5500_CS_PIN pin: W5500 CS pin */
    GPIO_InitStructure.GPIO_Pin = W5500_CS_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(W5500_CS_GPIO_PORT, &GPIO_InitStructure);

    /*!< SPI configuration */
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;

    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_Init(W5500_SPI, &SPI_InitStructure);

    /*!< Enable the W5500_SPI  */
    SPI_Cmd(W5500_SPI, ENABLE);

    GPIO_ResetBits(GPIOB, W5500_RESET_PIN);
    Delay(0xEFFFFF); 
    GPIO_SetBits(GPIOB, W5500_RESET_PIN);
}

W5500 Driver에서 SPI Interface를 위한 Call Back 함수 및 초기화 함수를 src 디렉토리 내에 w5500_init.c 파일을 생성하여 구현한다.
W5500 Driver 에서 SPI Call back 함수로 등록될 함수들

static uint8_t wizchip_rw(uint8_t byte)
{
    /*!< Loop while DR register in not emplty */
    while (SPI_I2S_GetFlagStatus(W5500_SPI, SPI_I2S_FLAG_TXE) == RESET);

    /*!< Send byte through the SPI2 peripheral */
    SPI_I2S_SendData(W5500_SPI, byte);

    /*!< Wait to receive a byte */
    while (SPI_I2S_GetFlagStatus(W5500_SPI, SPI_I2S_FLAG_RXNE) == RESET);

    /*!< Return the byte read from the SPI bus */
    return SPI_I2S_ReceiveData(W5500_SPI);
}

static void  wizchip_select(void)
{
    GPIO_ResetBits(W5500_CS_GPIO_PORT, W5500_CS_PIN);
}

static void  wizchip_deselect(void)
{
    GPIO_SetBits(W5500_CS_GPIO_PORT, W5500_CS_PIN);
}

static void  wizchip_write(uint8_t wb)
{
    wizchip_rw(wb);
}

static uint8_t wizchip_read(void)
{
    return wizchip_rw(0xFF);
}

W5500 초기화 함수

void W5500_Init(void)
{
    /*!< Deselect the FLASH: Chip Select high */
    wizchip_deselect();

    // Wiznet
    reg_wizchip_cs_cbfunc(wizchip_select, wizchip_deselect);
    reg_wizchip_spi_cbfunc(wizchip_read, wizchip_write);

    /* wizchip initialize*/
    uint8_t tmp;
    uint8_t memsize[2][8] = { {2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2}};

    if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1) {
        myprintf("WIZCHIP Initialized fail.\r\n");
        return;
    }

    /* PHY link status check */
    do {
        if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1) {
            myprintf("Unknown PHY Link status.\r\n");
            return;
        }
    } while (tmp == PHY_LINK_OFF);
}

Network 정보 설정 함수

void display_Net_Info()
{
    wiz_NetInfo gWIZNETINFO;

    ctlnetwork(CN_GET_NETINFO, (void*) &gWIZNETINFO);
    myprintf("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]);
    myprintf("IP: %d.%d.%d.%d\r\n", gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3]);
    myprintf("GW: %d.%d.%d.%d\r\n", gWIZNETINFO.gw[0], gWIZNETINFO.gw[1], gWIZNETINFO.gw[2], gWIZNETINFO.gw[3]);
    myprintf("SN: %d.%d.%d.%d\r\n", gWIZNETINFO.sn[0], gWIZNETINFO.sn[1], gWIZNETINFO.sn[2], gWIZNETINFO.sn[3]);
    myprintf("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, 1, 100 },                               // IP address
        { 192, 168, 1, 1},                                  // Gateway
        { 255, 255, 255, 0},                                // Subnet mask
        { 8, 8, 8, 0},                                      // DNS Server
    };

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

    display_Net_Info();
}

main 함수

int main(int argc, char* argv[])
{
    RCC_Configuration();
    USART1_Configuration();
    W5500_SPI_Init();

    W5500_Init();   
    Net_Conf();

    while(1)
    {
    }
}

porting9

코드를 작성 완료 후 프로젝트를 빌드하면, 프로젝트 디렉토리 내의 Debug 디렉토리에 “프로젝트명.bin” 파일이 생성된다. 이 파일이 Firmware 바이너리 파일이며, stm32flash utility를 이용하여 Flash에 Fusing 한다. 다음 명령을 수행하여 Flash Fusing 한다.

# stm32flash –w w5500_project.bin –v /dev/ttyUSB0 –b 115200

porting10

Firmware가 정상적으로 Fusing이 되었으면, Ping을 통해 정상적으로 W5500 Chip이 동작하는지 확인할 수 있으며, UART로 네트워크 설정 정보들이 출력 된다.

porting11

porting12

프로젝트 파일 : 다운로드

STM32 MCU 보드에서 W5500 사용하기 (2부)”에 대한 4개의 생각

  1. 김재현

    W5500를 STm32에 사용하려고하는데 컴파일해서 네트워크 설정값을 확인해보면
    설정값이 아닌 일정 고정값으로 출력되는데,,,,무슨 이유가 있을까요?

    응답
    1. damduc 글쓴이

      현재 사용하시는 코드나 환경이 어떠신지 몰라 정확하게 판단하기 힘드네요 ㅠ.ㅜ
      W5500 Datasheet를 참조 하셔서, 실제 IP를 설정하는 Register에 제대로 IP가 설정되었는지 확인해보시는게 좋을 것 같습니다.

      응답

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

This site uses Akismet to reduce spam. Learn how your comment data is processed.