태그 보관물: porting

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

프로젝트 파일 : 다운로드