<목차>

1. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(1)

2. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(2)

3. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(3)

4. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(4)

5. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(5)

6. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(6)

7. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(7)

8. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(8)

 

 

5. 포팅하기 - Loopback (Echo Server) 구현하기

 

지난 시간 W5500에 대한 Ping Test까지 완료하였다. 이제 본격적으로 ioLibrary를 활용하여 실제 응용을 구현해보자.

 

- TCP Loopback (Echo Server) 구현하기

Loopback 은 수신한 데이타를 아무런 가공없이 그대로 되돌려주는 Echo Server 프로그램이다.

Echo Server는 TCP Server나 Client 그리고 UDP등으로 구현이 가능한다.

Echo Server에서 Protocol은 말그대로 수신한 데이타를 아무런 가공없이 그대로 수신한 상대방에게 돌려 주는 것이다. 일반적으로 Telnet, FTP, HTTP, NTP 등과 같은 Protocol은 정해진 Data를 수신하고 그것을 해석하고 그에 상응하는 Data를 가공하여 상대방에 돌려준다. 여기서는 그런 Protocol의 구현에 앞서 가장 간단한 Echo Server를 구현해 볼것이다.

 

TCP Echo Server를 구현하기 위해 필요한 함수를 먼저 살펴보자. 각 SOCKET API들은 앞서 언급한 SOCKET_APIs.chm Doxygen 문서를 참조하라. 이 모든 함수는 Blocked (Polling) 혹은 Non-Blocked Mode로 선택적으로 함수를 사용할 수 있다. 이와 관련된 Post은 다음에 하는 것으로 하고, 우선, socket() 함수 호출 시 즉 생성시 flag 설정 시 SF_IO_NONBLCOK 값을 추가해주면 된다. flag 설정시 SF_IO_NONBLOCK을 추가하지 않을 경우, 즉 Default로 설정할 경우 SF_IO_BLOCK으로 설정된다. 또한 Socket 의 IO Mode는 setsockopt() 함수를 이용하여 동작 중에도  설정이 가능하다.

/* Socket Creatatiion */
int8_t    socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag);

/* Listen to a TCP client */
int8_t    listen(uint8_t sn);

/* Connect to a server */
int8_t   connect(uint8_t sn);

/* Send data to the peer */
int32_t  send(uint8_t sn, uint8_t* buf, uint32_t len);

/* Receive data from the peer */
int32_t  recv(uint8_t sn, uint8_t* buf, uint32_t len);

/* Disconnect the socket only used in TCP */
int8_t   disconnect(uint8_t sn);

/* Close the socket without disconnect-processing */
int8_t   close(uint8_t sn);

 

WIZnet은 TCP 관련 Application 구현 시 참고 할 수 있는 Skeleton code를 아래와 같이 제공한다.

{
    ...
    switch(getSn_SR(sn)) {
    case SOCK_ESTABILSHED:         /* TCP ESTABLISHED */
        /* TCP Server Side : When acceptting from a peer to request to connection */
        /* TCP Cleint Side :  When the connection request is acceptted by the server */ 
        //
        // TODO
        //
        // Start to data communication
        send(sn, buf, len);  // or recv(sn,buf,len)
        recv(sn,buf, len);    // or send(sn,buf,len)
        break;
    case SOCK_CLOSE_WAIT:
        /* Disconnect request  : The socket don't need any more */
        disconnect(sn);      // Don't returned until the disconnect is succeeded. 
        // or close(sn);      // Without processing to disconnect to the peer
        break;
    case SOCK_CLOSED:          /* Socket Closed State */
        /* TCP Server Side */
        socket(sn, Sn_MR_TCP,server_port, 0x00);  // Block-Io
        /* TCP Client Side : any_port is random because this can't be used as same as the previous port num */
        //socket(sn, Sn_MR_TCP,any_port, SF_IO_NONBLOCK);   // Non-Block-IO
        //
        // TODO
        //
        break;
    case SOCK_INIT:         /* TCP Socket Creatation */
        /* TCP Server Side : Wait to a conenctiion request from a peer */
        listen(sn);      
        /* TCP Client Side : Reqeust to connect to the server with server_port num */
        connect(sn,server_ip_address, server_port);  // Don't return until the connection is success
        //
        // TODO
        //
        break;
    case SOCK_LISTEN:        /* TCP Server Mode : This state can be omitted*/
        //
        // TODO
        //
        break;
    }
    ...
}

TCP Sever Skeleton 코드를 참고하여 아래와 같이 구현하여 보자.

///////////////////////////////////////////////////////////////
// Loopback Test Example Code using ioLibrary_BSD			 //
///////////////////////////////////////////////////////////////
int32_t loopback_tcps(uint8_t sn, uint8_t* buf, uint16_t port)
{
   int32_t ret;
   uint16_t size = 0, sentsize=0;
   switch(getSn_SR(sn))
   {
      case SOCK_ESTABLISHED :
         if(getSn_IR(sn) & Sn_IR_CON)
         {
            printf("%bu:Connected\r\n",sn);
            setSn_IR(sn,Sn_IR_CON);
         }
         if((size = getSn_RX_RSR(sn)) > 0)
         {
            if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
            ret = recv(sn,buf,size);
            if(ret <= 0) return ret;
            sentsize = 0;
            while(size != sentsize)
            {
               ret = send(sn,buf+sentsize,size-sentsize);
               if(ret < 0)
               {
                  close(sn);
                  return ret;
               }
               sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.
            }
         }
         break;
      case SOCK_CLOSE_WAIT :
         printf("%bu:CloseWait\r\n",sn);
         if((ret=disconnect(sn)) != SOCK_OK) return ret;
         printf("%bu:Closed\r\n",sn);
         break;
      case SOCK_INIT :
    	  printf("%bu:Listen, port [%u]\r\n",sn, port);
         if( (ret = listen(sn)) != SOCK_OK) return ret;
         break;
      case SOCK_CLOSED:
         printf("%bu:LBTStart\r\n",sn);
         if((ret=socket(sn,Sn_MR_TCP,port,0x00)) != sn)
            return ret;
         printf("%bu:Opened\r\n",sn);
         break;
      default:
         break;
   }
   return 1;
}

다소 복잡해 보이지만 getSn_RX_RSR() 함수의 사용 그리고 Return에 따른 에러 처리를 무시하고 코드를 살펴보면 Skeleton Code를 그대로 볼 수 있다. getSn_RX_RSR()함수 사용은 현재 Non-Block IO mode로 동작하는 recv() 함수가 Blocked 되는 것을 방지하기 위해 미리 수신한 크기를 확인하고 확인 후 recv() 함수를 호출하도록 구현되었다.

 

 

- UDP Loopback (Echo Server) 구현하기

UDP Echo Server를 구현하기 위해 필요한 함수를 먼저 살펴보자. SOCKET_API.chm 참조. TCP와 마찬가지로 Blocked 혹은 Non-blocked로 사용 가능하다.

/* Socket Creatatiion */
int8_t    socket(uint8_t sn, uint8_t protocol, uint16_t port, uint8_t flag);

/* Send data to a peer */
int32_t  sendto(uint8_t sn, uint8_t* buf, uint32_t len, uint8_t* addr, uint16_t port);

/* Receive data from the peer */
int32_t  recvfrom(uint8_t sn, uint8_t* buf, uint32_t len, uint8_t* addr, uint16* port);

/* Close the socket without disconnect-processing */
int8_t   close(uint8_t sn);

 

다음은 UDP 관련 Application 구현 시 참고할 수 있는 아주 간단한 Skeleton Code를 아래와 같이 제공한다.

{
    ...
    switch(getSn_SR(sn)) {
    case SOCK_UDP:         /* TCP Socket Creatation */
        //
        // TODO
        //
        // Start to data communication
        sendto(sn, buf, len, peer_ip_address, peer_port_num);     // or recvfrom(...);
        recvfrom(sn,buf, len, peer_ip_address, peer_port_num);    // or sendto(...);
        //
        // If the socket don't need any more
        if(is_closed) close(sn);
        //
        break;
    case SOCK_CLOSED:          /* Socket Closed State */
        /* TCP Server Side */
        socket(sn, Sn_MR_UDP,server_port, 0x00);  // Block-Io
        /* TCP Client Side : any_port is random because this can't be used as same as the previous port num */
        //socket(sn, Sn_MR_TCP,any_port, SF_IO_NONBLOCK);   // Non-Block-IO
        //
        // TODO
        //
        break;
    }
    ...
}

UDP Skeleton Code를 참고하여 UDP Loopback을 아래와 같이 구현해 보자.

int32_t loopback_udps(uint8_t sn, uint8_t* buf, uint16_t port)
{
   int32_t  ret;
   uint16_t size, sentsize;
   uint8_t  destip[4];
   uint16_t destport;
   //uint8_t  packinfo = 0;
   switch(getSn_SR(sn))
   {
      case SOCK_UDP :
         if((size = getSn_RX_RSR(sn)) > 0)
         {
            if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
            ret = recvfrom(sn,buf,size,destip,(uint16_t*)&destport);
            if(ret <= 0)
            {
               printf("%bu: recvfrom error. %ld\r\n",sn,ret);
               return ret;
            }
            size = (uint16_t) ret;
            sentsize = 0;
            while(sentsize != size)
            {
               ret = sendto(sn,buf+sentsize,size-sentsize,destip,destport);
               if(ret < 0)
               {
                  printf("%bu: sendto error. %ld\r\n",sn,ret);
                  return ret;
               }
               sentsize += ret; // Don't care SOCKERR_BUSY, because it is zero.
            }
         }
         break;
      case SOCK_CLOSED:
         printf("%bu:LBUStart\r\n",sn);
         if((ret=socket(sn,Sn_MR_UDP,port,0x00)) != sn)
            return ret;
         printf("%bu:Opened, port [%u]\r\n",sn, port);
         break;
      default :
         break;
   }
   return 1;
}

 

- Loopback (Echo Server) Test 하기

앞서 구현된 loopback_tcps() loopback_udp() 함수를 ioLibrary_W5500_main.c 의 함수 선언부에 추가하고 Loopback을 위한 Data buffer를 변수 선언부에 추가한다. Data buffer 크기는 Target System에 맞게 적절히 조절한다.

/////////////////////////////////////////
// SOCKET NUMBER DEFINION for Examples //
/////////////////////////////////////////
#define SOCK_TCPS        0
#define SOCK_UDPS        1

////////////////////////////////////////////////
// Shared Buffer Definition for LOOPBACK TEST //
////////////////////////////////////////////////
#define DATA_BUF_SIZE   2048
uint8_t gDATABUF[DATA_BUF_SIZE];

 

또한  main() 함수의 main loop에 Loopback 기능을 수행할 수 있도록 다음과 같이 추가한다.

 ...
	/* Network initialization */
	network_init();

	/*******************************/
	/* WIZnet W5500 Code Examples  */
	/* TCPS/UDPS Loopback test     */
	/*******************************/
                /* Main loop */
                while(1)
	{
    	uint32_t ret = 0;
    	/* Loopback Test */
    	// TCP server loopback test
    	if( (ret = loopback_tcps(SOCK_TCPS, gDATABUF, 5000)) < 0) {
			printf("SOCKET ERROR : %ld\r\n", ret);
		}

    	// UDP server loopback test
		if( (ret = loopback_udps(SOCK_UDPS, gDATABUF, 3000)) < 0) {
			printf("SOCKET ERROR : %ld\r\n", ret);
		}
	} // end of Main loop
	// NOTREACHED

	return 0;
}

 

모든 코드 구현이 완료되었다. Test를 위해 지난 번 소개한 Hercules Program을 사용할 할 것이다. 자 컴파일 후 프로그램을 다운로드하고 다음과 같이 Target Board를 실행 해보자.

 

1. Hercules 프로그램을 Serial 모드로 실행하고 Target Board를 동작 시키면 Target Board의 출력을 다음과 같이 확인할 수 있다.

 

 

2. 또 하나의 Hercules Program을 TCP client 모드로 실행한 후, Target 보드의 Network 정보를 입력하고 접속을 시도해보자. 접속을 성공하였다면 "Hello, W5500!!!" 을 Target Board로 전송하면 Taget Board로 부터 되 돌아 오는 "Hello, W5500!!!"을 다음과 같이 확인 할 수 있다.

 

 

3. UDP Loopback을 테스트하기 위해서 또 하나의 Hercules Program을 UDP mode로 실행하고, TCP와 동일하게 Target Board의 Nework 정보를 입력한 후 [Listen] 버튼을 클린한다. UDP 채널이 성공적으로 만들어 졌다면, TCP와 동일하게 "Hello, W5500!!!"을 Target Board로 전송하고 되돌아 오는 "Hello, W5500!!!"을 다음과 같이 확인하자.

 

 

 

이상 W5500 용 ioLibrary를 C8051F380 보드로 Porting하고 간단한 TCP Loopback (Echo server) Example 구현까지 해 보았다. 글을 마치며, 좀더 자세한 설명과 사용법에 미흡한 점이 없지 않으나, 8051 사용자들에게 도움이 되길 바란다.

 

프로젝트 다운로운 

ioLibrary_W5500_For_8051.zip

 

ioLibrary는 http://wizwiki.net/ 이나 https://github.com/bingdo/ioLibrary 에서 최신 버전을 적용하기 바란다.

 

< PREV

저작자 표시 동일 조건 변경 허락
신고
블로그 이미지

밤소 MidnightCow

위즈네트 칩(W5300, W5200, W7100, W7500) 개발자

<목차>

1. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(1)

2. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(2)

3. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(3)

4. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(4)

5. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(5)

6. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(6)

7. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(7)

8. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(8)

 

 

5. 포팅하기 - W5500 초기화

 

지난 시간 W5500 SPI 통신 검증에 있어 VERSIONR 레지스터의 Read가 되지 않는 것을 확인하였다.

우선적으로 SPI  통신에 무슨 문제가 있는지 Debugging 한 후 W5500 초기화 과정을 거쳐 Loopback Example까지 구현해보자.

 

- W5500 SPI interface 검증

Hardware 연결 상태는 정상이다. 근데 왜 동작하지 않을까? SPI Clock을 조정해보자.

현재 12MHz로 동작하나, 이를 8MHz, 4MHz 등 으로 낮추어 테스트 해보자.

SPI clcok은 Configuratioin Wizard2 tool의 [Peripherals >> SPI] 이용하여 SPI0CKR  값을 조절 해보면서 Test를 진행해보자. 그 결과 , 12MHz로 동작하는 것과 동일한 결과를 볼 수 있다. 고로 단순 SPI Clock 문제는 아닌 것으로 판단된다. SPI DATA signal의 MOSI와 MISO 핀 설정에 문제가 있는지 확인해보자.

W5500의 SPI signal SCSn, SCLK, MOSI, MISO  들은 Pin Description 상으로 Pull-up/down 처리에 대한 설명이 없는 것으로 보아 내부에 따로 처리되어 있는 것 같지 않다.  C8051F380의 SPI signal들은 Configuration Wizard2 의 [Peripherals >> Port I/O] 를 이용하여 PIN map이나 Pull-up/down 처리 등을 확인해보자.

W5500 ioLibrary_BSD을 MCU 8051로 포팅하기(5) 참조. SCK를 제외한 나머지 신호들이 모두 Pull-up 처리되어 있다. 여기서 Output으로 사용되는 핀들은 Pull-up을 Input으로 사용되는 핀들은 Open-drain으로 다음과 같이 설정을 바꾸어 보자.

 

 

P0MDOUT = 0x0E P0MDOUT = 0x1D로 변경되었다. ioLibrary_W5500_main.c에서 Port_IO_Init() 함수를 새로 생성된 함수로 대체한다. 

void Port_IO_Init()
{
    // P0.0  -  SCK  (SPI0), Push-Pull,  Digital
    // P0.1  -  MISO (SPI0), Open-Drain, Digital
    // P0.2  -  MOSI (SPI0), Push-Pull,  Digital
    // P0.3  -  NSS  (SPI0), Push-Pull,  Digital
    // P0.4  -  TX0 (UART0), Push-Pull,  Digital
    // P0.5  -  RX0 (UART0), Open-Drain, Digital
    // P0.6  -  Unassigned,  Open-Drain, Digital
    // P0.7  -  Unassigned,  Open-Drain, Digital

    // P1.0  -  Unassigned,  Push-Pull,  Digital
    // P1.1  -  Unassigned,  Open-Drain, Digital
    // P1.2  -  Unassigned,  Open-Drain, Digital
    // P1.3  -  Unassigned,  Open-Drain, Digital
    // P1.4  -  Unassigned,  Open-Drain, Digital
    // P1.5  -  Unassigned,  Open-Drain, Digital
    // P1.6  -  Unassigned,  Open-Drain, Digital
    // P1.7  -  Unassigned,  Open-Drain, Digital

    // P2.0  -  Unassigned,  Open-Drain, Digital
    // P2.1  -  Unassigned,  Open-Drain, Digital
    // P2.2  -  Unassigned,  Open-Drain, Digital
    // P2.3  -  Unassigned,  Open-Drain, Digital
    // P2.4  -  Unassigned,  Open-Drain, Digital
    // P2.5  -  Unassigned,  Open-Drain, Digital
    // P2.6  -  Unassigned,  Open-Drain, Digital
    // P2.7  -  Unassigned,  Open-Drain, Digital

    // P3.0  -  Unassigned,  Open-Drain, Digital
    // P3.1  -  Unassigned,  Open-Drain, Digital
    // P3.2  -  Unassigned,  Open-Drain, Digital
    // P3.3  -  Unassigned,  Open-Drain, Digital
    // P3.4  -  Unassigned,  Open-Drain, Digital
    // P3.5  -  Unassigned,  Open-Drain, Digital
    // P3.6  -  Unassigned,  Open-Drain, Digital
    // P3.7  -  Unassigned,  Open-Drain, Digital

    P0MDOUT   = 0x1D;
    P1MDOUT   = 0x01;
    XBR0      = 0x03;
    XBR1      = 0x40;
}

수정된 Program을 Board로 다운로드하고 다시 테스트해보자. Serial 출력이 다음과 같이 출력되고 더 이상 진행이 없다.  이것은 제대로 동작해서 그럴수도 있고, 어딘가 또 모를 곳에서 무한루프를 돌 수 있다.

 

Welcome to W5500 ioLibrary Porting Guide for 8051 Users
WIZCHP TEST : Registeration Callback func

 

Debugging Tool을 이용하여 MCU를 Break 해보자. 다행히 SPI 검증코드를 모두 통과하고 다음과 같이 while loop를 돌고 있음을 확인할 수 있다. 이것으로 C8051F380과 W5500의 SPI 통신은 어느정도 검증되었다.

 

 

 

- W5500 초기화

W5500 초기화 과정은 아주 간단한다. W5500 Reset이 완료되었다면,

Network 통신에 가장 기본이 MAC Local IP, Gateway IP address 와 Subnet mask 값을 설정하여 한다.

그외 필요에 따라 각 SOCKET에 할당되어질 Buffer Size를 지정하거나, Network Timeout 값등을 지정한다.

일반적으로 Socket Buffer Size나 Timeout 값은 Reset 값을 그대로 사용한다.

ioLibrary의 Extra function을 사용할 수 있지만, 코드 크기를 좀더 줄이고 싶다면 Extra funtion 대신 setXXX()/getXXX() 와 같은 basic I/O function을 이용할 수 도 있다.

ioLibrary_W5500_main.c 에서

선언부에 다음과 같이 추가한다. 이때 Keil-C compiler는 structure member 초기화가 제대로 이루어 지지 않기 때문에 main()에서 별도로 초기화한다. 다른 개발환경을 쓸 경우 초기값을 직접 선언해 줄수 있다.

WIZ550io 사용자들은 따로 Network 정보를 초기화 필요는 없다. 이는 WIZ550io 자체적으로 Unique한 MAC 주소와 Default IP address들을 가지고 있기 때문이다. 여기서는 초기화과정을 설명하기 위해서 아래와 같이 변경하도록 한다. 단 MAC 주소는 반드시 공인된 MAC을 사용하길 바란다.

wiz_NetInfo xdata gWIZNETINFO;/* = { {0x10, 0x11, 0x12,0x13, 0x14, 0x15},
                            {192, 168, 1, 119},
                            {255,255,255,0},
                            {192, 168, 1, 1},
                            {0,0,0,0},
                            NETINFO_STATIC }; */

 

/////////////////////////////////////////////////////////////
// Intialize the network information to be used in WIZCHIP //
/////////////////////////////////////////////////////////////
void network_init(void)
{
   uint8_t tmpstr[6];
	ctlnetwork(CN_SET_NETINFO, (void*)&gWIZNETINFO);
	ctlnetwork(CN_GET_NETINFO, (void*)&gWIZNETINFO);

	// Display Network Information
	ctlwizchip(CW_GET_ID,(void*)tmpstr);
	printf("\r\n=== %s NET CONF ===\r\n",(char*)tmpstr);
	printf("MAC: %02bX:%02bX:%02bX:%02bX:%02bX:%02bX\r\n",gWIZNETINFO.mac[0],gWIZNETINFO.mac[1],gWIZNETINFO.mac[2],
		  gWIZNETINFO.mac[3],gWIZNETINFO.mac[4],gWIZNETINFO.mac[5]);
	printf("SIP: %bu.%bu.%bu.%bu\r\n", gWIZNETINFO.ip[0],gWIZNETINFO.ip[1],gWIZNETINFO.ip[2],gWIZNETINFO.ip[3]);
	printf("GAR: %bu.%bu.%bu.%bu\r\n", gWIZNETINFO.gw[0],gWIZNETINFO.gw[1],gWIZNETINFO.gw[2],gWIZNETINFO.gw[3]);
	printf("SUB: %bu.%bu.%bu.%bu\r\n", gWIZNETINFO.sn[0],gWIZNETINFO.sn[1],gWIZNETINFO.sn[2],gWIZNETINFO.sn[3]);
	printf("DNS: %bu.%bu.%bu.%bu\r\n", gWIZNETINFO.dns[0],gWIZNETINFO.dns[1],gWIZNETINFO.dns[2],gWIZNETINFO.dns[3]);
	printf("======================\r\n");
}
/////////////////////////////////////////////////////////////

 

main() 함수에서 기검증된 SPI I/F 검증부를 주석처리하거나 삭제하고, 다음과 같이 초기화과정을 추가한다.

int main (void)
{
	uint8_t xdata memsize[2][8] = {{2,2,2,2,2,2,2,2},{2,2,2,2,2,2,2,2}};
	
	gWIZNETINFO.mac[0] = 0x10;
	gWIZNETINFO.mac[1] = 0x11;
	gWIZNETINFO.mac[2] = 0x12;
	gWIZNETINFO.mac[3] = 0x13;
	gWIZNETINFO.mac[4] = 0x14;
	gWIZNETINFO.mac[5] = 0x15;
	gWIZNETINFO.ip[0] = 192;
	gWIZNETINFO.ip[1] = 168;
	gWIZNETINFO.ip[2] = 1;
	gWIZNETINFO.ip[3] = 119;
	gWIZNETINFO.sn[0] = 255;
	gWIZNETINFO.sn[1] = 255;
	gWIZNETINFO.sn[2] = 255;
	gWIZNETINFO.sn[3] = 0;
	gWIZNETINFO.gw[0] = 192;
	gWIZNETINFO.gw[1] = 168;
	gWIZNETINFO.gw[2] = 1;
	gWIZNETINFO.gw[3] = 1;
	gWIZNETINFO.dns[0] = 0;
	gWIZNETINFO.dns[1] = 0;
	gWIZNETINFO.dns[2] = 0;
	gWIZNETINFO.dns[3] = 0;
	gWIZNETINFO.dhcp = NETINFO_STATIC;
	
	Init_Device();

	printf("Welcome to W5500 ioLibrary Porting Guide for 8051 Users\r\n");

	WIZChip_HW_Reset();

	printf("WIZCHP TEST : Registeration Callback func\r\n");
	//reg_wizchip_cris_cbfucn(0,0); // No-use in example
	reg_wizchip_cs_cbfunc(wizchip_select,wizchip_deselect);
	reg_wizchip_spi_cbfunc(SPI0_ReadByte,SPI0_WriteByte);


	/* W5500 Access Test */
	// This code should be commented after testing W5500 access //
	/*
	if(getVERSIONR() != 0x04)
	{
		printf("ACCESS ERR: VERSIONR != 0x04, Read value=%02bx\r\n", getVERSIONR());
		while(1);
	}

	if(getRCR() != 0x08)
	{
		printf("ACCESS ERR: RCR != 0x08, Read value=%02bx\r\n",getRCR());
		while(1);
	}
	if(getRTR() != 0x07D0)
	{
		printf("ACCESS ERR: RTR != 0x07D0, Read value=%04x\r\n", getRTR());
		while(1);
	}

	setRCR(0xA5);
	setRTR(0x5A5A);
	if(getRCR() != 0xA5)
	{
		printf("ACCESS ERR: RCR != 0xA5, Read value=%02bx\r\n",getRCR());
		while(1);
	}
	if(getRTR() != 0x5A5A)
	{
		printf("ACCESS ERR: RTR != 0x5A5A, Read value=%04x\r\n", getRTR());
		while(1);
	}
	/////////////////////////////////////////////////////////////////////
    */
	/* WIZCHIP SOCKET Buffer initialize */
	
	if(ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) == -1)
	{
	   printf("WIZCHIP Initialized fail.\r\n");
	   while(1);
	}
	/* PHY link status check */
	printf("Link Check...");
	do
	{
	   if(ctlwizchip(CW_GET_PHYLINK, (void*)&tmp) == -1)
		  printf("Unknown PHY Link stauts.\r\n");
	}while(tmp == PHY_LINK_OFF);
	printf("OK\r\n");
	
	/* Network initialization */
	network_init();
	
	while (1) {}                             // Spin forever

	// NOTREACHED

	return 0;
}

여기까지 추가를 하고 Compile한후 다시 보드로 다운로드해보자. 아무 문제 없이 마쳤다면,

테스트하는 PC의 Network 정보 역시 W5500과 같은 Subnet에 있도록 수정한다. Test PC와 Test Board를 허브나 스위치 없이 바로 연결할 경우는 Test Board 아이피를 제외한 임의의 IP를 설정해도 된다. 다만 허브나 스위치등을 통해 연결할 경우 IP 주소가 다른 사람들과 겹치지 않도록 주의하여 설정한다. Test PC 의 Network 설정 방법은 여기서 설명하지 않겠다.(Google등을 통해 검색하면 관련 자료가 많이 있으니 참조하라).

성공적으로 다운로드를 했다면 Dos prompt 창을 이용하여 Ping test를 해보자.

 

 

ctrlwizchip() 함수는 Socket buffer size, Network Information, Phy Link Status 확인과 같은 여러 기능을 수행하도록 구현되어 있다. 하지만 이와 같은 Extra Function은 W5500 basic I/O functiion으로 얼마든지 대체될 수 있다. 한가지 예로 ctlwizchip(CW_INIT_WIZCHIP,(void*)memsize) 을 basic I/O function으로 변경해보자. wizchip_conf.c 파일을 참조하면 쉽게 구현할 수 있다.

int8_t wizchip_init(uint8_t* txsize, uint8_t* rxsize)
{
   int8_t i;
   int8_t tmp = 0;
   wizchip_sw_reset();
   if(txsize)
   {
      tmp = 0;
      for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++)
         tmp += txsize[i];
      if(tmp > 16) return -1;
      for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++)
         setSn_TXBUF_SIZE(i, txsize[i]);
   }
   if(rxsize)
   {
      tmp = 0;
      for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++)
         tmp += rxsize[i];
      if(tmp > 16) return -1;
      for(i = 0 ; i < _WIZCHIP_SOCK_NUM_; i++)
         setSn_RXBUF_SIZE(i, rxsize[i]);
   }
   return 0;
}

 

이제까지 C8051F380과 W5500의 Driver Porting과정과 Test 방법등을 알아 보았다. 다음시간 실제 Loopback (Echo server)을 구현해보고 W5500의 실사용에 대해 알아보자.

 

< PREV                                                                                                                                     NEXT >

저작자 표시 동일 조건 변경 허락
신고
블로그 이미지

밤소 MidnightCow

위즈네트 칩(W5300, W5200, W7100, W7500) 개발자

<목차>

1. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(1)

2. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(2)

3. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(3)

4. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(4)

5. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(5)

6. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(6)

7. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(7)

8. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(8)

 

 

5. 포팅하기 - W5500   I/O control function 구현하기

 

 

W5500에 초기화에 앞서 Debugging및 Logging을 위한 printf() 함수를 먼저 등록해본다.

 

일반적으로 printf() & scanf() 함수를 사용하기 위해서는 getchar() & putchar() 함수를 Target System에 맞게 구현한 후 overriding 해주어야 한다. 하지만, Simplicitity Studio IDE 는 단순히 stdio.h 파일만 include해주면 된다.(아마 getchar()& putchar()가 이미 8051 에 맞게 수정되어 있을 것이다)

 

ioLibaray_W5500_main.c 에서

#include 부에 아래와 같이 #include <stdio.h>를 추가한다.

 

#include <compiler_defs.h>
#include <SI_C8051F380_Register_Enums.h>                // SFR declarations
#include <stdio.h> 

 

main() 함수에 printf() 문을 다음과 같이 추가한다.

 
int main (void)
{
	Init_Device();
	
	printf("Welcome to W5500 ioLibrary Porting Guide for 8051 Users\r\n");

	while (1) {}                             // Spin forever

	// NOTREACHED

	return 0;
}

 

 

- C8051F380의 SPI 사용하기

W5500 을 제어하기 위해서 C8051F380의 SPI read/write 함수가 필요하다. Datasheet를 보면서 직접 구현해보는 것도 좋지만, Simplicity Studio에서 SPI 사용에 대한 Example을 제공한다.

 

 

Copy된 Project를 보면 SPI를 어떻게 사용하는지 알수 있다.

일반적으로 UART나 I2C, SPI 같은 Serial 통신 Peripheral은 Data 레지스터와 Status 레지스터들의 단순 제어로 쉽게 통신할 수 있다.

C8051F380의 SPI0은 Data 레지스터 SPI0DAT, Status 레지스터 SPI0CN_SPIF 두개로 제어된다. 또한 /SCS 제어를 위해 SPI0CN_NSSMD0 레지스터를 제공한다.

다음 코드는 SPI 인터페이를 이용한 EEPROM read/write example Code이다. 이를 참조하여 W5500 제어용 SPI read/write 함수를 작성할 것이다.

 

U8 EEPROM_Read (U16 address)
{
   // Reading a byte from the EEPROM is a three-step operation.

   // Step1: Send the READ command
   SPI0CN_NSSMD0   = 0;                 // Activate Slave Select
   SPI0DAT  = EEPROM_CMD_READ;
   while (!SPI0CN_SPIF);
   SPI0CN_SPIF     = 0;

   // Step2: Send the EEPROM source address (MSB first)
   SPI0DAT = (U8)((address >> 8) & 0x00FF);
   while (!SPI0CN_SPIF);
   SPI0CN_SPIF     = 0;
   SPI0DAT = (U8)(address & 0x00FF);
   while (!SPI0CN_SPIF);
   SPI0CN_SPIF     = 0;

   // Step3: Read the value returned
   SPI0DAT  = 0;                       // Dummy write to output serial clock
   while (!SPI0CN_SPIF);               // Wait for the value to be read
   SPI0CN_SPIF     = 0;
   SPI0CN_NSSMD0   = 1;                // Deactivate Slave Select
   Delay_us (1);

   return SPI0DAT;
}

 

- ioLibrary Todo List

자 본격적으로 W5500을 제어하기 위해 ioLibrary를 어떻게 사용해야 하는지 알아보자.

앞서 다운로드 받은 ioLibrary 의 Doxygen 문서 SOCKET_APIs.chm에서 Todo List 항목을 살펴보자.

 

 

Todo List는 ioLibrary를 WIZnet가 공급하는 Chip 들중은 원하는 칩 즉 W5500으로 설정하기 위한 각종 정의 및 정보들을 설정하고  칩 제어에 필요한 io call-back funtion들을 등록 사용하는 방법을설명하고 있다. 아래와 같이 wizchip_conf.h 파일에서 하나씩 W5500으로 변경해보자.

 


 1. WIZnet Chip 선택

    _WIZCHIP_ 을 W5500 으로 선택한다.

    #define _WIZCHIP_ 5500 

 

2. WIZnet Chip의 IO BASE 선택

    IO BASE는 Parallel Bus를 사용할 경우에만 정의한다. SPI mode를 사용하므로 무시.

 

3. WIZnet Chip IO mode 선택

    W5500은 SPI mode 두가지 Variable Data Mode(VDM)와 Fixed Data Mode(FDM)을 지원한다. 여기서는 SCS

   를 사용하는 VDM을 선택한다.

     #define _WIZCHIP_IO_MODE_ _WIZCHIP_IO_MODE_SPI_VDM_

 

4. WIZnet Chip IO control call-back function 등록

    사용자 구현 call-back 함수를 등록하지 않을 경우 ioLibrary가 정의한 Default 함수가 동작한다.

 

    4.1.   reg_wizchip_bus_cbfunc(uint8_t(*bus_rb)(uint32_t addr),

                             void(*bus_wb)(uint32_t addr, uint8_t wb))

           _WIZCHIP_IO_MODE_가 Bus Mode (_WIZCHIP_IO_MODE_BUS_ ,

         _WIZCHIP_IO_MODE_BUS_DIR_ _WIZCHIP_IO_MODE_BUS_INDIR_)로 정의 되었을 때

          사용자가 구현한 Read/Write 함수 등록. Bus mode를 사용하지 않으므로 무시

    4.2.  reg_wizchip_cris_cbfunc(void(*cris_en)(void), void(*cris_ex)(void))

          이 함수는 WIZnet Chip  I/O 제어 시 interrupt 등으로 부터 간섭을 피하기 위한 Critical session 시작/끝을

          알려 주는 함수를 등록한다. 여기서는 Interrupt를 사용하지 않기 때문에 무시한다.

          필요하다면 Intterupt disable(EA=0) enable(EA=0) 등으로 구현한다.

    4.3 .  reg_wizchip_cs_cbfunc(void(*cs_sel)(void), void(*cs_desel)(void))

          WIZnet Chip Select control call-back function 등록함수이다.

          W5500은 SPI를 사용하므로 SCS 제어 함수를 등록한다.

    4.4. reg_wizchip_spi_cbfunc(uint8_t(*spi_rb)(void), void(*spi_wb)(uint8_t wb))

           WIZnet Chip SPI 제어 Call-back 함수를 등록한다. W5500은 SPI를 사용하므로 반드시 사용자 구현 SPI

           read/write call-back 함수를 등록해야 한다.

 

- W5500 제어를 위한 Call-back 함수 구현

wizchip_conf.h 에서 W5500을 위한 define을 마무리한 후,

iolibrary_W5500_main.c에 W5500 제어를 위한 I/O call-back function 을 구현하자. Todo List에 설명한 것처럼 SCS 신호 제어와 SPI byte read/write 함수가 필요하다.

 

void wizchip_select(void)
{
	SPI0CN_NSSMD0   = 0;
}

void wizchip_deselect(void)
{
	SPI0CN_NSSMD0   = 1;
}

void SPI0_WriteByte(uint8_t dat)
{
	SPI0DAT  = dat;
	while (!SPI0CN_SPIF);
	SPI0CN_SPIF     = 0;
}

uint8_t SPI0_ReadByte(void)
{
	SPI0DAT  = 0;
	while (!SPI0CN_SPIF);
	SPI0CN_SPIF     = 0;
	return SPI0DAT;
}

 

- C8051F380 GPIO를 이용한 W5500 Reset 제어 함수 구현

W5500 Reset Signal은 C8051F380 GPIO P1_0과 연결되어 있다. 따라서 P1_0를 WIZNET_RESET_PIN으로 재정의하고 이를 제어하여 W5500 Hardware reset 함수를 구현하자.

 

ioLibaray_W5500_main.c 정의 부분에 다음과 같이 PIN 정의를 추가한다.

 

SBIT(WIZCHIP_RESET_PIN, SFR_P1, 0);

 

ioLibarary_W5500_main.c 에서 다음과 같이 void WIZChip_HW_Reset(void)를 구현한다

 

void WIZChip_HW_Reset(void)
{
	volatile uint16_t i;
	WIZCHIP_RESET_PIN = 0;
	for(i = 0; i < 0xFFFF; i++); // 20ms@48MHz
	WIZCHIP_RESET_PIN = 1;
	for(i = 0; i < 0xFFFF; i++); // 20ms@48MHz
	for(i = 0; i < 0xFFFF; i++); // 20ms@48MHz

}

 

- W5500 Reset 및 Call-back 함수 등록하기

reg_wizchip_xxx_cbfucn() 함수를 이용하여 앞서 구현된 Call-back fucntion을 등록하자.

ioLibrary_W5500_main.cmain()함수에 다음과 같이 구현한다.

 

int main (void)
{
	Init_Device();

	printf("Welcome to W5500 ioLibrary Porting Guide for 8051 Users\r\n");

	WIZChip_HW_Reset();

	printf("W5500 : Registeration Callback func\r\n");
	//reg_wizchip_cris_cbfucn(0,0); // No-use in example
	reg_wizchip_cs_cbfunc(wizchip_select,wizchip_deselect);
	reg_wizchip_spi_cbfunc(SPI0_ReadByte,SPI0_WriteByte);

	while (1) {}                             // Spin forever

	// NOTREACHED

	return 0;
}

여기서 Critical Session call-back funtion은 구현할 필요가 없기 때문에 따로 등록하지 않는다. 필요하다면 Critical Session call-back 함수를 구현하여 다음 처럼 등록하여 사용할 수 있다.

 

void W5500_Critical_Session_Enter(void) {  EA = 0; }

void W5500_Critical_Session_Exit(void)  { EA = 1; }

int main (void)
{
                // ...
	reg_wizchip_cris_cbfucn(W5500_Critical_Session_Enter,W5500_Critical_Session_Exit); 
	reg_wizchip_cs_cbfunc(wizchip_select,wizchip_deselect);
                // ...
	return 0;
}

 

- W5500 Access 검증하기

상기와 같이 ioLibrary  포팅이 완료되었다. 실제로 제대로 동작하는지 확인 필요하다.

Call-back으로 등록된 함수를 이용하여 W5500의 기본 레지스터등을 Access해보고 제대로 동작하는지 확인해 보자.

 

1. Read Test (Version 레지스터 읽기)

    VERSIONR은 Read Only 레지스터로 항상 0x04 값을 가진다.

    getVERSIONR() 이용

2. Write Test (RCR & RTR 레지스터 쓰고 읽기)

    RCR은 초기 0x08, RTR 0x07D0 값을 가진다. 먼저 읽어서 초기값이 맞는지 한번더 확인하고, 원하는

   값을  설정하여 설정값이 제대로 읽히는지 확인한다.

    setRCR() & setRTR() / getRCR() & getRTR() 이용

 

int main (void)
{
	Init_Device();

	printf("Welcome to W5500 ioLibrary Porting Guide for 8051 Users\r\n");

	WIZChip_HW_Reset();

	printf("WIZCHP TEST : Registeration Callback func\r\n");
	//reg_wizchip_cris_cbfucn(0,0); // No-use in example
	reg_wizchip_cs_cbfunc(wizchip_select,wizchip_deselect);
	reg_wizchip_spi_cbfunc(SPI0_ReadByte,SPI0_WriteByte);


	/* W5500 Access Test */
	// This code should be commented after testing W5500 access //
	if(getVERSIONR() != 0x04)
	{
		printf("ACCESS ERR: VERSIONR != 0x04, Read value=%02bx\r\n", getVERSIONR());
		while(1);
	}

	if(getRCR() != 0x08)
	{
		printf("ACCESS ERR: RCR != 0x08, Read value=%02bx\r\n",getRCR());
		while(1);
	}
	if(getRTR() != 0x07D0)
	{
		printf("ACCESS ERR: RTR != 0x07D0, Read value=%04x\r\n", getRTR());
		while(1);
	}

	setRCR(0xA5);
	setRTR(0x5A5A);
	if(getRCR() != 0xA5)
	{
		printf("ACCESS ERR: RCR != 0xA5, Read value=%02bx\r\n",getRCR());
		while(1);
	}
	if(getRTR() != 0x5A5A)
	{
		printf("ACCESS ERR: RTR != 0x5A5A, Read value=%04x\r\n", getRTR());
		while(1);
	}
	/////////////////////////////////////////////////////////////////////

	while (1) {}                             // Spin forever

	// NOTREACHED

	return 0;
}

 

Flash Programming & Debugging & Testing

자 이제 컴파일된 프로그램을 실제 보드로 다운로드하고 구현한대로 동작하는지 확인하자.

우선 보드를 다음과 연결하자.

 

 

연결을 마친 후, Hercules (Serial과 TCP/UDP 통신을 지원하는 프리웨어)를 실행시킨 후 다음 순서처럼 Serial Port를 Open한다.

 

 

Flash Image를 다운로드하고 Test 하기 위해서 다음 그림의 3까지 수행한다. 그럼 main() 함수내에 Init_Device() 전에 Break 되어 있다.

이제 4를 눌러 Hercules 창에 문자열이 출력되는지 확인하자. 자~~아  4를 꾸~~~욱 누른다.

 

 

기대와 전혀 다르게 아무런 반응이 없다. ㅠㅠ; 무슨일이 벌어지고 있는걸까?

나와야되는 시리얼 출력은 나오지 않고 당황스럽게도 MCU가 뭘하고 있는지 아무런 반응이 없다. (멘붕)

뭘 잘못한 건지 알수 없다.

 

자 당황하지 말고 Debugging Tool을 적극 활용해보자. Running 중인 MCU를 Break 한다. 어라 main() 어딘가에서 Break가 걸릴 거라 기대했는데, 전혀 엉뚱한 SILABS_STARTUP.A51 이란 startup code의 XDATA 영역 초기화 루틴을 맴돌고 있다. (또 다시 맨붕...)

 

자 잘 생각해보자. Startup code가 수행되고 있다는 것은 Reset이 걸렸다는 얘기. Watch-dog Reset이 의심스럽다. 조심히 데이타시트를 살펴보자.

 

 

역시 내 생각이 맞았다. Reset 타임에 Watchdog Timer가 Enable은 된다고 명시 되어있다. 이를 사용하지 않기 위해선 반드시 Explicitly disabled 해야된다. Watchdog Timer는 PCA module4를 이용하여 동작한다.

Configuration Wizard2 의 [ Peripheral >> PCA ]를 살펴보자.

 

 

나의 경험상 Init_Device() 함수에서 Watchdog disable Code를 넣는 것보단 Start-up code에 넣어두는 것이 원천적 으로 안전하다. SILABS_STARTUP.A51 파일에서 main 함수 Jump 전에 다음과 같이 코드를 삽입한다.

 

; Standard SFR Symbols
ACC     DATA    0E0H
B       DATA    0F0H
SP      DATA    81H
DPL     DATA    82H
DPH     DATA    83H
PCA0MD  DATA    0D9H

                NAME    ?C_STARTUP


?C_C51STARTUP   SEGMENT   CODE
?STACK                SEGMENT   IDATA

                           RSEG    ?STACK
                           DS      1

                           EXTRN CODE (?C_START)
                           PUBLIC  ?C_STARTUP

              CSEG    AT      0
?C_STARTUP:       LJMP    STARTUP1

              RSEG    ?C_C51STARTUP

STARTUP1:
    MOV     PCA0MD, #00H

$IF (SILABS_STARTUP = 1)
EXTRN CODE (SiLabs_Startup)
                LCALL  SiLabs_Startup
$ENDIF 

 

자 이제 기대를 품고 컴파일한 후 테스트 해보자. 헐~~ 역시 출력이 되지 않는다. 하지만 당황하지 말자. 우리에게는 강력한 Debugging Tool이 있다. 다시 한번 MCU를 Break를 해보자.

 

 

아까랑 다르게 Startup code에서 맴돌지 않는다. Watchdog Reset 문제는 해결되었다. 자 그럼 왜 Serial 출력이 되지 않는 걸까? Break된 Code를 살펴보자. 0x3FFF 주소에서 SCON.1 값이 1이 될때까지 무한 루프를 돌고 있다. 이것은 Serial 출력이 가능한 상태가 될때까지 기다리것이다. SCON.1 값이 Reset 시 1이 아닌것으로  판단 강제로 다음과 같이 1로 만들어준다. (일반적으로 reset시 TX  Flag  TI 는 1이지만 뭐... 쩝) 

ioLibrary_W5500_main.c에서 UART_Init()SCON0_T1 = 1 를 추가한다.

void UART_Init()
{
    SCON0     = 0x10;
    SCON0_TI = 1;
}

 

자 다시 고고싱 ~~~

드뎌 다음과 같이 시리얼이 출력된다.고생한 만큼 기쁨도 두배.

 

 

그러나 기쁨도 잠시. W5500 VERSIONR 레지스터 값을 제대로 읽어 오지 못한다. SPI Interface에 문제가 있나 보다.  다음시간에 계속 Debugging 해보자. 

 

 

< PREV                                                                                                           NEXT >

저작자 표시 동일 조건 변경 허락
신고
블로그 이미지

밤소 MidnightCow

위즈네트 칩(W5300, W5200, W7100, W7500) 개발자

<목차>

1. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(1)

2. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(2)

3. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(3)

4. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(4)

5. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(5)

6. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(6)

7. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(7)

8. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(8)

 

 

 

 

5. 포팅하기 - C8051F380 설정하기

 

 

ioLibrary 사용에 앞서 C8051F380을 사용하기 위한 MCU 기반 기본 설정(Main clock, UART, SPI, GPIO등)을 해야 한다.

 

W5500 제어를 위한 필요한 제원등을 살펴보면 다음과 같다.

   - Main Clock

   - W5500(WIZ550io) Reset , UART, SPI 등으로 사용될 GPIO  핀 설정

   - 간단한 Debugging을 위한 UART (printf 사용)

   - W5500 제어를 위한 SPI 

 

이 부분은 너무 걱정하지 않아도 되는 것이 앞서 언급된 Configuration Wizard2 tool을 이용하면 쉽게 할 수 있다. (여기 참조 : http://midnightcow.tistory.com/entry/W5500-ioLibraryBSD-8051-Porting-하기-2 )

 

자 그럼 지금부터 Configuration Wizard2를 이용하여 하나씩 설정해보자.

 

- Main Clock  (메뉴 선택 : Config Wizard  >> C8051F380 선택 >> Peripherals >> Oscillator)

 

C8051F380-TB 보드는 Y1 즉 External Clock이 없다. 따라서 내부 클럭을 선택해야 하는데 뭐가 있는지 알 수없다.

물론 데이타시트를 보고 내용을 파악할 수 있지만, Configruation Wizard2 tool에서 미루어 짐작할 수 있다.

 

Clock Source로 Internal H-F Oscillator를 선택한다.

 

SYSCLK으로 Internal H-F Oscillator를 선택한다. 그럼 SYSCLK speed가 48MHz로 표시된다.

Internal H-F 가 12MHz로 선택되고 SYSCLK speed가 48MHz이므로 내부 PLL이 4배로 동작하고 있음을 알 수 있다.

 

상기 설정을 마친 후 OK를 누르면 해당하는 코드가 다음과 같이 나타난다. 이를 복사해서 그대로 사용한다.

 

 

- W5500(WIZ550io) Reset , UART, SPI 등으로 사용될 GPIO  핀 설정

   (메뉴 선택 : ... >> Peripherals >> Port I/O)

W5500 Reset은 C8051F380 GPIO P1_0과 연결되어 있다. 이를 Digital Output으로 사용하기 위해 Pull-up 처리를 해준다. 이때 Crossbar Enable Check box를 체크해야 한다. 물론 체크하지 않았다 하더라도 OK를 누르는 순간 설정하라는 메시지창이 뜬다.

또한 UART와 SPI를 사용할 것이므로 UART0과 SPI0을 선택한다. SPI PIN들은 다른 Device와 공유될 수 있으므로 Pull-up 처리해준다. UART0과 SPI0은 기본 PIN을 그대로 사용한다. 물론 이핀들은 Pin SKIP 처리에 의해 원하는 것으로 이동도 가능하다.

설정 완료 후 OK를 누르면 Clock 설정과 같이 자동 생성된 코드가 추가된다.

 

 

 

- 간단한 Debugging을 위한 UART (printf 사용)  설정 (메뉴 선택 : ... >> Peripheral >> UART)

 

UART0 PIN 설정 완료 후 실제 통신에 필요한 설정을 해야 한다. 일반적으로 UART는 SYSCLK을 이용한 내부 Timer에 Baud rate가 결정되므로 Timer 설정도 같이 동반된다. UART는 단순 Debugging용으로 사용할 것이므로 Data bit 8, Baud rate 115200을 사용하도록 설정한다. 설정 완료 후 OK를 누르면 자동 생성된 코드가 추가된다.

 

 

 

- W5500 제어를 위한 SPI  (메뉴 선택 : ... >> Peripheral >> SPI)

마지막으로 W5500 제어를 위한 SPI 인터페이스를 설정한다. W5500은 SPI clock speed를 80MHz까지 지원한다고 되어 있다. C8051F380은 SYSCLK이 MAX 48MHz이므로 분주 클럭을 사용할 경우 최소 24MHz까지 설정 가능할 것으로 기대하나 실제 Jumper선으로 연결해서 인지 24MHz에서는 동작하지 않았다. 따라서 12MHz로 낮추어서 설정했다. 자 그럼 다음과 같이 설정해보자.

 

 

W5500은 SPI mode 0번과 3번을 지원한다. SPI mode 0 과 SPI mode 3은 모두 SPI clock이 Low인 동안 Data가 변할 수 있는 모드이고, 0번 인경우 SPI clock이 Low로 시작하고, 3인 경우는 High 상태로 시작한다. 더 궁금한 내용은 http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus를 참조하자.

3번 설정에서 W5500을 SPI mode 0으로 사용할 수 있도록 설정하였다.

 

 

이상 C8051F380 구동에 필요한 기본 정보 설정을 마쳤다. 이때 생성된 코드는 Project 의 main file인 ioLibrary_W5500_main.c 에 #include 문들과 main() 함수 사이에 복사한다.

void Timer_Init()
{
    TCON      = 0x40;
    TMOD      = 0x20;
    CKCON     = 0x08;
    TH1       = 0x30;
}

void UART_Init()
{
    SCON0     = 0x10;
}

void SPI_Init()
{
    SPI0CFG   = 0x40;
    SPI0CN    = 0x0D;
    SPI0CKR   = 0x01;
}

void Port_IO_Init()
{
    // P0.0  -  SCK  (SPI0), Open-Drain, Digital
    // P0.1  -  MISO (SPI0), Push-Pull,  Digital
    // P0.2  -  MOSI (SPI0), Push-Pull,  Digital
    // P0.3  -  NSS  (SPI0), Push-Pull,  Digital
    // P0.4  -  TX0 (UART0), Open-Drain, Digital
    // P0.5  -  RX0 (UART0), Open-Drain, Digital
    // P0.6  -  Unassigned,  Open-Drain, Digital
    // P0.7  -  Unassigned,  Open-Drain, Digital

    // P1.0  -  Unassigned,  Push-Pull,  Digital
    // P1.1  -  Unassigned,  Open-Drain, Digital
    // P1.2  -  Unassigned,  Open-Drain, Digital
    // P1.3  -  Unassigned,  Open-Drain, Digital
    // P1.4  -  Unassigned,  Open-Drain, Digital
    // P1.5  -  Unassigned,  Open-Drain, Digital
    // P1.6  -  Unassigned,  Open-Drain, Digital
    // P1.7  -  Unassigned,  Open-Drain, Digital

    // P2.0  -  Unassigned,  Open-Drain, Digital
    // P2.1  -  Unassigned,  Open-Drain, Digital
    // P2.2  -  Unassigned,  Open-Drain, Digital
    // P2.3  -  Unassigned,  Open-Drain, Digital
    // P2.4  -  Unassigned,  Open-Drain, Digital
    // P2.5  -  Unassigned,  Open-Drain, Digital
    // P2.6  -  Unassigned,  Open-Drain, Digital
    // P2.7  -  Unassigned,  Open-Drain, Digital

    // P3.0  -  Unassigned,  Open-Drain, Digital
    // P3.1  -  Unassigned,  Open-Drain, Digital
    // P3.2  -  Unassigned,  Open-Drain, Digital
    // P3.3  -  Unassigned,  Open-Drain, Digital
    // P3.4  -  Unassigned,  Open-Drain, Digital
    // P3.5  -  Unassigned,  Open-Drain, Digital
    // P3.6  -  Unassigned,  Open-Drain, Digital
    // P3.7  -  Unassigned,  Open-Drain, Digital

    P0MDOUT   = 0x0E;
    P1MDOUT   = 0x01;
    XBR0      = 0x03;
    XBR1      = 0x40;
}

void Oscillator_Init()
{
    FLSCL     = 0x90;
    CLKSEL    = 0x03;
    OSCICN    = 0xC3;
}

// Initialization function for device,
// Call Init_Device() from your main program
void Init_Device(void)
{
    Timer_Init();
    UART_Init();
    SPI_Init();
    Port_IO_Init();
    Oscillator_Init();
}

 

ioLibrary_W5500_main.c의 main() 함수에 다음과 같이 Init_Device()를 콜한다.

 

int main (void)
{
	Init_Device();

	while (1) {}                             // Spin forever

	// NOTREACHED

	return 0;
}

컴파일 후 에러가 없는지 확인한다.

다음 시간에 W5500을 ioLibrary를 이용하여 구동시켜 볼 것이다.

 

 

< PREV                                                                                                      NEXT >

저작자 표시 동일 조건 변경 허락
신고
블로그 이미지

밤소 MidnightCow

위즈네트 칩(W5300, W5200, W7100, W7500) 개발자

<목차>

1. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(1)

2. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(2)

3. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(3)

4. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(4)

5. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(5)

6. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(6)

7. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(7)

8. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(8)

 

 

5. 포팅하기 - ioLibrary Compile하기

 

앞 시간에는 작업 Project Directory에 ioLibrary를 설치하였다. 기본 구성이 끝났으므로 Project를 Build 해본다.

다음과 같이 17개의 Warning과 5개의 Error가 발생한다. 

 

C51 COMPILER V9.51 - SN: K1RIC-I06RWZ
COPYRIGHT Copyright (C) 2012 ARM Ltd and ARM Germany GmbH. All rights reserved.
*** WARNING C318 IN LINE 46 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.h: can't open file 'Ethernet/wizchip_conf.h'
make: *** [ioLibrary/Ethernet/W5500/w5500.OBJ] Error 1
*** ERROR C200 IN LINE 65 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: left side of '.' requires struct/union
*** WARNING C322 IN LINE 68 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 68 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 83 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 83 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** ERROR C320 IN LINE 93 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: "Unknown _WIZCHIP_IO_MODE_ in W5000. !!!"
*** WARNING C322 IN LINE 106 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 106 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 121 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 121 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** ERROR C320 IN LINE 131 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: "Unknown _WIZCHIP_IO_MODE_ in W5500. !!!"
*** WARNING C322 IN LINE 145 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 145 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 198 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 198 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** ERROR C320 IN LINE 208 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: "Unknown _WIZCHIP_IO_MODE_ in W5500. !!!!"
*** WARNING C322 IN LINE 222 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 222 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 275 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** WARNING C322 IN LINE 275 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: unknown identifier
*** ERROR C320 IN LINE 285 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.c: "Unknown _WIZCHIP_IO_MODE_ in W5500. !!!!"

 

C51 COMPILATION COMPLETE.  17 WARNING(S),  5 ERROR(S) 

 

당황하지 말고 하나씩 살펴보자.

첫번째 Warning "*** WARNING C318 IN LINE 46 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\W5500\w5500.h: can't open file 'Ethernet/wizchip_conf.h'"에서 wizchip_conf.h 파일을 열수 없단다. 이는 ioLibrary Directory가 Include Path에 포함되어 있지 않기 때문이다.

 

 

- ioLibrary Directory 를 Project의 Include Path에 포함시키기

 

Simplicity Studio IDE의 오른쪽 창 Project Explorer에서  Project "ioLibrary_W5500"을 선택하고 우클릭한다. 그러면 Pop-up Menu가 뜨고 거기서 Properties Menu를 클릭한다.

 

 

 

Properties 설정 창에서 다음과 같은 순서를 따라 ioLibrary Directory를 Include Path에 등록한다.

 

 

 

- Project Compile하기

 

Include Path 등록을 마친 후 다시 컴파일을 해보자. 다음과 같이 2개의 Warning과 1개의 Error로 줄어든다.

 

C51 COMPILER V9.51 - SN: K1RIC-I06RWZ
COPYRIGHT Copyright (C) 2012 ARM Ltd and ARM Germany GmbH. All rights reserved.
*** WARNING C322 IN LINE 132 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet/wizchip_conf.h: unknown identifier

C51 COMPILATION COMPLETE.  1 WARNING(S),  0 ERROR(S)
Finished building: ../ioLibrary/Ethernet/W5500/w5500.c
 
Building file: ../ioLibrary/Ethernet/socket.c
Invoking: Keil 8051 Compiler
C51 "@ioLibrary/Ethernet/socket.__i" || test $? -lt 2

C51 COMPILER V9.51 - SN: K1RIC-I06RWZ
COPYRIGHT Copyright (C) 2012 ARM Ltd and ARM Germany GmbH. All rights reserved.
*** WARNING C322 IN LINE 132 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet/wizchip_conf.h: unknown identifier
*** ERROR C141 IN LINE 56 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\socket.c: syntax error near ';'
make: *** [ioLibrary/Ethernet/socket.OBJ] Error 1
*** WARNING C322 IN LINE 266 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\socket.c: unknown identifier

C51 COMPILATION COMPLETE.  2 WARNING(S),  1 ERROR(S) 

 

첫번째 Warning을 살펴보자.

*** WARNING C322 IN LINE 132 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet/wizchip_conf.h: unknown identifier

 

wizchip_conf.h의 132번째 줄에 unknown identifier가 있단다.

_WIZCHIP_IO_MODE_BUS 정의에 오타가 있다. 이를  _WIZCHIP_IO_MODE_BUS_ 로 수정한다.

#if _WIZCHIP_IO_MODE_ & _WIZCHIP_IO_MODE_BUS
   #ifndef _WIZCHIP_IO_BASE_   
      #error "You should be define _WIZCHIP_IO_BASE_ to fit your system memory map.
   #endif
#endif

 

두번째 Error

*** ERROR C141 IN LINE 56 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\socket.c: syntax error near ';'

socket.c 파일에서 SOCK_AY_PORT_NUM 정의할 때 세미콜론(;)를 삭제한다.

#define SOCK_ANY_PORT_NUM 0xC000;

세번째 Warring

*** WARNING C322 IN LINE 266 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\socket.c: unknown identifier

socket.c 파일에서 _WZICHIP_ 오타를 _WIZCHIP_ 으로 수정

    

   if(tmp & Sn_IR_SENDOK)
   {
      setSn_IR(sn, Sn_IR_SENDOK);
      #if _WZICHIP_ == 5200
         if(getSn_TX_RD(sn) != sock_next_rd[sn])
         {
            setSn_CR(sn,Sn_CR_SEND);
            while(getSn_CR(sn));
            return SOCKERR_BUSY;
         }
      #endif
      sock_is_sending &= ~(1 << sn);
   }

Warning과 Error가 없을 때까지 Compile 작업을 반복 수행한다.

 

C51 COMPILER V9.51 - SN: K1RIC-I06RWZ
COPYRIGHT Copyright (C) 2012 ARM Ltd and ARM Germany GmbH. All rights reserved.
*** ERROR C141 IN LINE 57 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near ';'
*** ERROR C141 IN LINE 63 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near ';'
*** ERROR C141 IN LINE 69 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near ';'
*** ERROR C141 IN LINE 75 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near ';'
*** ERROR C141 IN LINE 83 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near ';'
*** ERROR C141 IN LINE 92 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near ';'
make: *** [ioLibrary/Ethernet/wizchip_conf.OBJ] Error 1
*** ERROR C141 IN LINE 99 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near ';'
*** ERROR C141 IN LINE 105 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near ';'
*** ERROR C141 IN LINE 112 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near '.'

C51 COMPILATION COMPLETE.  0 WARNING(S),  9 ERROR(S) 

 

8 Error

*** ERROR C141 IN LINE 57 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near ';'

wizchip_conf.c의 함수 구현시 {} 뒤에 세미콜론(;)이 붙어서 발생한 Error이므로 이를 모두 삭제한다.

 

void      wizchip_cris_enter(void)      {};

void      wizchip_cris_exit(void)        {};

void      wizchip_cs_select(void)      {};

void      wizchip_cs_deselect(void)   {};

uint8_t   wizchip_bus_readbyte(uint32_t AddrSel)   { return * ((volatile uint8_t *)((ptrdiff_t) AddrSel)); };

void      wizchip_bus_writebyte(uint32_t AddrSel, uint8_t wb)   { *((volatile uint8_t*)((ptrdiff_t)AddrSel)) = wb; };

uint8_t   wizchip_spi_readbyte(void)   {return 0;};

void      wizchip_spi_writebyte(uint8_t wb) {};

 

 

1 Error

*** ERROR C141 IN LINE 112 OF D:\UTILs\TMP\WORK\SiLab\ioLibrary_W5500_For_8051\ioLibrary\Ethernet\wizchip_conf.c: syntax error near '.'

이 에러는 KEIL-C compiler가 다음과 같은 STRUCTURE memberd의 초기값 설정을 지원하지 않기 때문에 발생한다.

따라서, 이 코드를 1차 배열 Assign으로 수정한다. 

_WIZCHIP  WIZCHIP =
      {
      .id                  = _WIZCHIP_ID_,
      .if_mode             = _WIZCHIP_IO_MODE_,
      .CRIS._enter         = wizchip_cris_enter,
      .CRIS._exit          = wizchip_cris_exit,
      .CS._select          = wizchip_cs_select,
      .CS._deselect        = wizchip_cs_deselect,
      .IF.BUS._read_byte   = wizchip_bus_readbyte,
      .IF.BUS._write_byte  = wizchip_bus_writebyte
//    .IF.SPI._read_byte   = wizchip_spi_readbyte,
//    .IF.SPI._write_byte  = wizchip_spi_writebyte
      };

 

 Structure member 를 삭제하고 1차배열로 할당한 코드이다.

_WIZCHIP  WIZCHIP =
{
   _WIZCHIP_IO_MODE_,
   _WIZCHIP_ID_,
   wizchip_cris_enter,
   wizchip_cris_exit,
   wizchip_cs_select,
   wizchip_cs_deselect,
   wizchip_bus_readbyte,
   wizchip_bus_writebyte,
 //wizchip_spi_readbyte,
 //wizchip_spi_writebyte
};

 

위 작업을 마무리한 후 다시 컴파일 해본다.  헐 아래와 같이 18 Warning과 155 ERROR가 발생한다. 

 *** ERROR L105: PUBLIC REFERS TO IGNORED SEGMENT
make: *** [ioLibrary_W5500.omf] Error 1
    SYMBOL:  ?_WIZ_RECV_DATA?BYTE
    SEGMENT: ?DT?_WIZ_RECV_DATA?W5500

*** ERROR L105: PUBLIC REFERS TO IGNORED SEGMENT
    SYMBOL:  ?_WIZ_SEND_DATA?BYTE
    SEGMENT: ?DT?_WIZ_SEND_DATA?W5500

*** ERROR L105: PUBLIC REFERS TO IGNORED SEGMENT
    SYMBOL:  ?_WIZCHIP_WRITE_BUF?BYTE
    SEGMENT: ?DT?_WIZCHIP_WRITE_BUF?W5500

*** ERROR L105: PUBLIC REFERS TO IGNORED SEGMENT
    SYMBOL:  ?_WIZCHIP_READ_BUF?BYTE
    SEGMENT: ?DT?_WIZCHIP_READ_BUF?W5500

*** ERROR L105: PUBLIC REFERS TO IGNORED SEGMENT
    SYMBOL:  ?_WIZCHIP_WRITE?BYTE
    SEGMENT: ?DT?_WIZCHIP_WRITE?W5500

Program Size: data=323.0 xdata=0 code=11868
LINK/LOCATE RUN COMPLETE.  18 WARNING(S),  155 ERROR(S)

 

18 Warning은 전부 *** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS  인 것으로 호출되지 않은 함수에 관한 경고이다. 이는 코드 동작에 전혀 문제가 없는 Warning으로 이 Warning을 없애고자한다면 해당 Function을 찾아 모두 주석 처리해주면 된다. 여기서는 그냥 사용한다.

 

155 에러는 Data Segment Error로 각 Function에서 할당되어진 Data나 전역 변수등이 8051의 128 Data  영역에 할당되어 Data overflow를 야기시는 에러이다. Silab C8051F380은 4 KB 영역의 Exteranl Data(XDATA) 영역을 지원하므로 Keil-C compile의 DATA model과 Code model을 모두 Large로 변경한다.  앞서 설명한 Properties 창에서 설정을 변경해보자.

 

- Data & Code Model 변경하기

 

 

 

 

이상 ioLibray_BSD compile을 성공적으로 마무리 했다.

다음 시간에는 WIZnet가 제공하는 Loopback example을 포팅해보면서 생기는 문제점을 하나씩 살펴보면 해결해 나갈 것이다.

 

 

< PREV                                                                                                           NEXT >

저작자 표시
신고
블로그 이미지

밤소 MidnightCow

위즈네트 칩(W5300, W5200, W7100, W7500) 개발자

<목차>

1. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(1)

2. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(2)

3. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(3)

4. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(4)

5. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(5)

6. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(6)

7. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(7)

8. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(8)

 

 

4. ioLibrary Download

 

위즈네트는 위키 사이트(http://wizwiki.net/wiki/) 를 운영하고 있으며, 위즈네트 제품에 대한 설명과 다양한 자료를 제공하고 있다.

자 그럼 포팅에 필요한 ioLibrary를 위즈네트위키에서 다운로드 받아 보자.

http://wizwiki.net/wiki/doku.php?id=products:w5500:driver 에서 최신 ioLibrary를 다운 받는다.

 

 

 

다운로드된 ioLibrary의 Ethernet V1.0.3을 압축해제 후 앞서 만들어둔 Project Directory에 ioLibrary Directory를 만들어 복사해 두자.

 

 

이제 ioLibrary를 다운로드하고 해당 Project Directory로 복사를 하였으니 모든 Porting 준비는 완료된 셈이다.

다음 시간 Project 환경에 ioLibrary를 추가하고 본격적으로 Porting을 해보기로 하자.

 

 

 

< PREV                                                                                                        NEXT >

저작자 표시
신고
블로그 이미지

밤소 MidnightCow

위즈네트 칩(W5300, W5200, W7100, W7500) 개발자

<목차>

1. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(1)

2. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(2)

3. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(3)

4. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(4)

5. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(5)

6. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(6)

7. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(7)

8. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(8)

 

3. Test Board 만들기

 

먼저 SiLab사의 C8051F380-TB board와 WIZnet사의 WIZ550io 모듈을 준비하고, Breadboard나 만능키트, 점퍼선등을 준비해 둔다.

 

C8051F380-DK board는 다행히 모든 IO PIN들이 PIN Header (J2, J3,J4,J5,J6) 5개로 모두 나와있으며 또한 96PIN PCN connector(J13)에도 나와 있다. 다행이 PCN connector를 보유하고 있어 Breadboard와 연결하여 사용할 예정이다. 이 Connector가 없을 시는 J3~J6 PIN Header와 Jumper선을 사용하여 연결해도 무방하다.

 

http://www.silabs.com/Support%20Documents/TechnicalDocs/C8051F38x-DK.pdf 

 

 

 

C8051F380의 IO 핀들은 기본적으로 GPIO 핀으로 사용되며, CrossBar 를 통해 SPI나 UART 기타 Peri등의 IO 핀으로 Switching 될 수 있다. Crossbar 설정에 따라 PIN의 위치가 변경되므로 Test 보드를 만들기 전에 SPI IO 핀들이 어떤 포트로 연결되는지 숙지하여야 한다. 다행히 Simplicity Studio의 Configuration Wizard2라는 Tool을 지원한다.

 

Configuration Wizard2를 실행하여 C8051F380을 선택한다.

 

 

[OK] 버튼을 누르면 Menu에 Peripherals가 추가 되고 하위메뉴 Port I/O를 선택하면 다음처럼 Port I/O 핀을 설정할 수 있다.

 

 

Pin Skip Check Box를 이용해 SPI IO 핀들을 원하는 포트 핀으로 이동할 수 있는 장점이 있다.

여기서는 Serial Debugging Message 출력을 위해 UART0 을 P0_4(TXD), P0_5(RXD)로 선택하고, SPI IO는 Port Skip 없이 기본설정으로 P0_0(SCLK), P0_1(MISO), P0_2(MOSI), P0_3(NSS)로 설정한다.

Configuration Wizard2 가장 큰 매력은 설정된 핀에 따른 Register 설정 코드를 자동으로 생성해준다는 것이다. 이것은 UART & SPI 드라이버를 구현할 때 많은 도움이 된다. 이부분은 계속 언급될 것이므로 이정도만 알고 패스~~~!!!

 

 

WIZ550io는 WIZnet사의 W5500 칩을 기반을 하는 Network Module이다. WIZ550io는 SPI 인터페이스만을 지원하고, Open source hardaware platform인 Arduino, GR-Kurumi, LaunchPad에 장착될 수 있는 Shield I/F board도 함께 지원한다. 또한 Arduino Sketch Library 로 포팅되어 있어 손쉽게 개발할 수 있다.(http://wizwiki.net/wiki/doku.php?id=ioshield)

 

WIZ550io의 상세 스펙은 http://wizwiki.net/wiki/doku.php?id=products:wiz550io:allpages 를 참조한다.

 

 

 

자 그럼 이제부터 본격적인 Test Board를 만들어 보자.

보드 제작에 앞서 간단한 회로도를 만들어 보자. 물론 회로도 없이 간단히 만들수도 있지만, 시간이 지나면 어떻게 만들었는지 기억이 나지 않는 경우가 대부분이기 때문에 나중을 위해서라도 간단하게나마 회로도를 작성하는 습관을 가져야 한다.

 

 

 

WIZ550io의 RSTn과 INTn 핀들은 각각 C8051F380의 P1_0과 P0_6 핀들로 연결한다. 이때 WIZ550io RDY 핀은 사용하지않는다.

 

<주의> RDY핀은 WIZ550io 자체 MCU가 W5500의 Network configuration을 완료했을때  High로 된다. RDY PIN은 보다 안정적인 WIZ550io 제어를 위한 Option PIN이다. 개발코저하는 Target B/D의 GPIO 핀이 부족할 경우 GPIO 핀에 연결하지않고 대신 200ms 정도 Delay를 준 후 WIZ550io를 Access해도 무방하다.

 

핀 연결을 다시 한번 정리하면.... 

 

 Signal Name

C8051F380 PIN 위치

 WIZ550io PIN 위

SPI : SCLK

P0_0 (J13:C12, J2:1) 

J1:5

 SPI : MISO

P0_1 (J13:B12, J2:2)

J1:4 

SPI : MOSI

P0_2  (J13:A12, J2:3)

J1:3

 SPI : SCS

P0_3 (J13:C11, J2:4)

J1:6 

 Interrupt

P0_6 (J13:C10, J2:7)

J2:5 

 RESET

P1_0(J13:C21, J3:1)

J2:3 

 3.3 VDD

J13:A1  

J1:7, J1:8, J2:1 

 GND

J13:B1

 

 

자 이제 회로도가 완성되었으니, 점퍼선을 이용하여 실수 없이 납땜하여 잘 연결해 보도록 하자.

보드를 만들고 전원을 인가하기 전에 반드시 단선이 없는지 회로도대로 연결되었는지, VDD와 GND는 쇼트되지 않았는지 확인하자.

 

 

 

드디어 테스트 보드 완성.  짜잔 !!! (물론 이보드 제작는 Dokkodai님이 도와주셨슴돠!!!)

긴장된 맘으로 WIZ550io를 연결한 후 Power를 인가한다.  별 문제없으면 통과...휴==3

 

 

 

자 이제 MCU 8051에 ioLibrary_BSD 를 포팅할 모든 준비가 끝났다.

다음 연재에 계속 ~~~

 

 

< PREV                                                                                                          NEXT >

저작자 표시
신고
블로그 이미지

밤소 MidnightCow

위즈네트 칩(W5300, W5200, W7100, W7500) 개발자

<목차>

1. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(1)

2. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(2)

3. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(3)

4. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(4)

5. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(5)

6. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(6)

7. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(7)

8. W5500 ioLibrary_BSD를 MCU 8051로 포팅하기(8)

 

음~~~ 8051 포팅이라!!! (당황하지 말고 팍 쭉~~~)

무엇부터 해야 하나 생각을 정리해 둘 필요가 있다. 차근차근 하나씩 정리해보자.

 

- 수많은 8051 MCU 중에 무엇을 선택하나 ?

- 8051 개발 환경은 무엇으로 하나?

- Test Board 만들기

- ioLibrary 다운로드

- Porting 시작

 

1. 수많은 8051 MCU 중에 무엇을 선택하나 ?

 

8051 MCU는 이미 많이 보편화되어 개발자라면 누구나 익숙한 MCU이다. 각 Vendor마다 조금씩의 특징이 있다. 고속 처리가 가능한 것도 있으며, 다양한 peri를 가지고 있는 것도 있다. 아주 오래 전 Atmel과 Dallas의 8051를 써본 경험이 있긴 하지만, 현재 보유하고 있는 보드는 Silab사의 C8051F380이다. 나도 이녀석은 처음으로 사용해본다. (살짝 긴장되긴 하네^^)

C8051F380의 특징적 제원을 간략히 살펴보면,

 

High Speed 8051 μC Core
- Pipelined instruction architecture; executes 70% of instructions in 1 or 2 system clocks
- Up to 48 MIPS operation
- Expanded interrupt handler

Memory
- 4352 or 2304 Bytes RAM
- 64, 32, or 16 kB Flash; In-system programmable in 512-byte sectors

Digital Peripherals
- 40/25 Port I/O; All 5 V tolerant with high sink current
- Hardware enhanced SPI™, two I2C/SMBus™, and two enhanced UART serial ports
- Six general purpose 16-bit counter/timers
- 16-bit programmable counter array (PCA) with five capture/compare modules
- External Memory Interface (EMIF)

 

최대 48MIPS 까지 지원한다고 하니 최대 Clock은 48MHz까지 사용할 수 있는 것으로 보인다. 또한 SRAM 역시 4K 이상 지원되며, Code Flash 역시 64KB까지 지원된다. (여기서는 Data 4K, Code 64K 를 사용한다 - Network 응용을 개발하기 위해 넉넉한 크기를 준비). 무엇보다도 중요한 것은 W5500 Access를 위한 SPI Interface를 지원한다는 것. 그 밖의 각종 Peri들이 많이 있으나, USB, 온도센서 및 ADC가 있다는 정도로 알자.

<C8051F380 DK Board>

 

 

 

2. 8051 개발 환경은 무엇으로 하나?

 

8051 개발환경은 Keil, IAR, sdcc 등 다양하게 존재한다. 하지만, C8051F380은 SiLab사의 MCU인 만큼 SiLab에서 제공하는 Simplicity Studio를 이용하여 개발한다.

먼저 SiLab Homepage에서 Simplicity Stuido 2.0을 다운로드한다.

http://www.silabs.com/products/mcu/Pages/simplicity-studio.aspx

자신의 OS에 맞는 Simplicity Studio를 다운로드 한 후 설치한다.

설치 및 사용법에 대해서는 자세한 설명은 생략한다. (Silab이나 인터넷 관련 동영상 및 자료가 많이 있으니 참고하시길...)

 

 

Simplicity IDE는 Silab 자체 제작 Complier를 사용하지 않고, Keil-C compiler를 사용한다. Silab사의 Install Guide에 따라 Keil-C complier를 설치하고 Silab에 지원하는 License Key를 등록한다. 이로써, 정식 Licence가 등록된 Keil-C complier를 사용할 수 있다.

 

Simplicity Studio의 가장 큰 장점은 개발 환경 뿐만 아니라, 각종 Datasheet, Application 문서, Example Code 및 개발에 필요한 각종 Resouce 등을 통합 관리하여 항상 최신 정보를 개발자로 하여금 놓치지 않도록 해준다는 것이다.

 

<주의>

Keil이나 다른 개발환경을 사용할 경우 C8051F380과같은 Silab Chip들에 대한 Device 정보를 제공하지 않을 수도 있다. 물론 제공하지 않는다고 해서 개발할 수 없는 것은 아니다. 하지만 미리 잘 만들어진 Header, C file 및 각종 Libarary가 있는데 사서 고생할 필요없지 않는가?

Simplicity Sudio를 사용하지 않더라도 우선 설치해주자.

그럼 "C:\SiliconLabs\SimplicityStudio\v2\developer\sdks\si8051\v2\Device" 경로로 Silab에 미리 잘 만들어둔 각종 Header/C 및 Library를 손쉽게 사용할 수 있다.

 

Simplicity Studio에서 Simplicity IDE Double click하여실행하여 간단한 새로운 Project를 만들어 보자.

 

Menu>Project>New>Silcon Labs MCU Project... 를 이용하여 앞으로 만들 Project의 제원을 설정해준다.

 

앞으로 Porting 하게 될 보드는 "C8051F380 Development Kit" 이므로 이것을 선택.

 

Project 명과 Working directory를 설정한 후 Finish.

 

C8051F380 용 startup code와 Main 파일이 project에 자동으로 추가되었으며, Toolbar의 망치 아이콘을 눌러 Compile한다.

Error없이 Compile이 잘된다. Compile된 Binary Image를 Silab에서 제공하는 USB Debug Adapter로 Board로 Download해보자.

우선 아래 그림과 같이 USB Debug를 연결한다. (이때 USB 장치가 자동으로 인식되고 Driver가 자동으로 깔린다)

 

USB Debug를 성공적으로 인식했다면 IDE 에서 풍뎅이 모양 아이콘을 눌러 생성된 이미지를 보드로 다운로드. 보드 다운로드를 성공하면 Break point를 설정하여 원하는 코드를 Debugging할 수 있다. IC 모양 아이콘은 Debugging 없이 보드로 다운로드만 한다.

 

이것으로 ioLibrary를 포팅할 개발 환경은 준비가 되었다. 다음 시간 WIZ550io와 C8051F380-TB 보드와 연결을 해보자.

 

                                                                                                                                            NEXT >

 

신고
블로그 이미지

밤소 MidnightCow

위즈네트 칩(W5300, W5200, W7100, W7500) 개발자