본문 바로가기

RaspberryPi/RP2350

[RP2350_W6100] Pi Pico C/C++ SDK - W6100의 Iperf TCP Throughput 측정 테스트

[RP2350_W6100] 보드는 RP2350에 W6100을 포함하고 있는 테스트 보드이므로 Raspberry Pi Pico C/C++ SDK 개발환경 에서 W6100 개발환경을 설정하고 TCP 전송률 성능을 측정해 보자.

 

우선 Pi Pico SDK로 W6100 테스트 예제를 생성한다. 하드웨어 세팅에서 SPI, DMA 를 체크하자.

 

 

 

그리고 W6100관련 io6Library  라이브러리를 다운 받는다. 

 

W6100과 관련된 Ethernet 폴더를 생성한 프로젝트에 복사한다.

 

그리고 라이브러리를 Cmake 파일에 추가 등록 하면 된다.

include_directories(
    Ethernet
    Ethernet/w6100
    )

# Add executable. Default name is the project name, version 0.1

add_executable(rp2350_w6100 rp2350_w6100.c
w6x00_spi.c
Ethernet/wizchip_conf.c
Ethernet/socket.c
Ethernet/w6100/w6100.c
)

 

 


 

W6100 관련 기본 개발환경 설이 완료 되었다면 W6100 CS 핀 설정 및 SPI Read/Write함수를 재정의 해 준다.

 #define SPI_PORT spi0
 
 #define PIN_SCK 18
 #define PIN_MOSI 19
 #define PIN_MISO 16
 
 #define PIN_CS 2
 #define PIN_RST 3
 
static uint8_t wizchip_read(void)
{
    uint8_t rx_data = 0;
    uint8_t tx_data = 0xFF;

    spi_read_blocking(SPI_PORT, tx_data, &rx_data, 1);

    return rx_data;
}

static void wizchip_read_buf(uint8_t* rx_data, datasize_t len)
{
    uint8_t tx_data = 0xFF;

    spi_read_blocking(SPI_PORT, tx_data, rx_data, len);
}

static void wizchip_write(uint8_t tx_data)
{
    spi_write_blocking(SPI_PORT, &tx_data, 1);
}

void wizchip_write_buf(uint8_t* tx_data, datasize_t len)
{
    spi_write_blocking(SPI_PORT, tx_data, len);
}

 

 

RP2350에서 W6100 을이용한 TCP loopback 테스트 코드로 TCP 전송률을 측정해 보자.

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include "hardware/uart.h"

#include "hardware/clocks.h"
#include "hardware/pll.h"

#include "wizchip_conf.h"
#include "socket.h"
#include "w6x00_spi.h"

// SPI Defines
// We are going to use SPI 0, and allocate it to the following GPIO pins
// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments
#define SPI_PORT spi0

#define PIN_MISO 16
#define PIN_CS   17
#define PIN_SCK  18
#define PIN_MOSI 19

// UART defines
// By default the stdout UART is `uart0`, so we will use the second one
#define UART_ID uart1
#define BAUD_RATE 115200


#define PLL_SYS_KHZ (150 * 1000)

/* Network */
static wiz_NetInfo g_net_info =
    {
        .mac = {0x00, 0x08, 0xDC, 0x12, 0x34, 0x56}, // MAC address
        .ip = {192, 168, 1, 104},                     // IP address
        .sn = {255, 255, 255, 0},                    // Subnet Mask
        .gw = {192, 168, 1, 1},                     // Gateway
        .dns = {8, 8, 8, 8},                         // DNS server
        .lla = {0xfe, 0x80, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x02, 0x08, 0xdc, 0xff,
                0xfe, 0x57, 0x57, 0x25},             // Link Local Address
        .gua = {0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00},             // Global Unicast Address
        .sn6 = {0xff, 0xff, 0xff, 0xff,
                0xff, 0xff, 0xff, 0xff,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00},             // IPv6 Prefix
        .gw6 = {0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00},             // Gateway IPv6 Address
        .dns6 = {0x20, 0x01, 0x48, 0x60,
                0x48, 0x60, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x88, 0x88},             // DNS6 server
        .ipmode = NETINFO_STATIC_ALL
};

#define LED1_PIN            25
#define Led1Off()           gpio_put(LED1_PIN, 1);
#define Led1On()            gpio_put(LED1_PIN, 0);

#define SOCKET_LOOPBACK 0
#define PORT_LOOPBACK 5001

#define ETHERNET_BUF_MAX_SIZE (1024 * 1)
#define DATA_BUF_SIZE			ETHERNET_BUF_MAX_SIZE

static uint8_t g_loopback_buf[ETHERNET_BUF_MAX_SIZE] = {
    0,
};

int32_t loopback_tcps(uint8_t sn, uint8_t* buf, uint16_t port)
{
   int32_t ret;
   uint16_t size = 0, sentsize=0;

#ifdef _LOOPBACK_DEBUG_
   uint8_t destip[4];
   uint16_t destport;
#endif

   switch(getSn_SR(sn))
   {
      case SOCK_ESTABLISHED :
         if(getSn_IR(sn) & Sn_IR_CON)
         {
#ifdef _LOOPBACK_DEBUG_
			getSn_DIPR(sn, destip);
			destport = getSn_DPORT(sn);

			printf("%d:Connected - %d.%d.%d.%d : %d\r\n",sn, destip[0], destip[1], destip[2], destip[3], destport);
#endif
			setSn_IR(sn,Sn_IR_CON);
         }
		 if((size = getSn_RX_RSR(sn)) > 0) // Don't need to check SOCKERR_BUSY because it doesn't not occur.
         {
			if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
			ret = recv(sn, buf, size);

			if(ret <= 0) return ret;      // check SOCKERR_BUSY & SOCKERR_XXX. For showing the occurrence of SOCKERR_BUSY.
			size = (uint16_t) 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 :
#ifdef _LOOPBACK_DEBUG_
         printf("%d:CloseWait\r\n",sn);
#endif
         if((ret = disconnect(sn)) != SOCK_OK) return ret;
#ifdef _LOOPBACK_DEBUG_
         printf("%d:Socket Closed\r\n", sn);
#endif
         break;
      case SOCK_INIT :
#ifdef _LOOPBACK_DEBUG_
    	 printf("%d:Listen, TCP server loopback, port [%d]\r\n", sn, port);
#endif
         if( (ret = listen(sn)) != SOCK_OK) return ret;
         break;
      case SOCK_CLOSED:
#ifdef _LOOPBACK_DEBUG_
         //printf("%d:TCP server loopback start\r\n",sn);
#endif
         if((ret = socket(sn, Sn_MR_TCP, port, 0x00)) != sn) return ret;
#ifdef _LOOPBACK_DEBUG_
         //printf("%d:Socket opened\r\n",sn);
#endif
         break;
      default:
         break;
   }
   return 1;
}


int main()
{
    stdio_init_all();

    gpio_init(LED1_PIN);
    gpio_set_dir(LED1_PIN, GPIO_OUT);
    // SPI initialisation. This example will use SPI at 1MHz.
    
    spi_init(SPI_PORT, 1000*1000);
    gpio_set_function(PIN_MISO, GPIO_FUNC_SPI);
    gpio_set_function(PIN_CS,   GPIO_FUNC_SIO);
    gpio_set_function(PIN_SCK,  GPIO_FUNC_SPI);
    gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
    
    // Chip select is active-low, so we'll initialise it to a driven-high state
    gpio_set_dir(PIN_CS, GPIO_OUT);
    gpio_put(PIN_CS, 1);


    gpio_put(LED1_PIN, 1);
    sleep_ms(500);
    gpio_put(LED1_PIN, 0);
    sleep_ms(500);
    
    gpio_init(0);
    gpio_set_dir(0, GPIO_OUT);    

    printf("W6100 Test\n");

    // For more examples of UART use see https://github.com/raspberrypi/pico-examples/tree/master/uart
    wizchip_spi_initialize();
    wizchip_cris_initialize();

    wizchip_reset();
    wizchip_initialize();
    wizchip_check();

    network_initialize(g_net_info);

    /* Get network information */
    print_network_information(g_net_info);
    while (true) {
        if ((retval = loopback_tcps(SOCKET_TCP_SERVER, g_tcp_server_buf, PORT_TCP_SERVER, AS_IPV4)) < 0)
        {
            printf(" loopback_tcps error : %d\n", retval);

            while (1);
        }
    }
}

 

 

Raspberry Pi Pico C/C++ SDK 개발환경 에서 R2350을이용한 W6100의 TCP loopback 테스트 결과 5Mps 로 측정된다.
왜 이렇게 느리지? RP2350의 Arduino IDE 에서 TCP 전송율과 비교해서 별 차이점이 없는것 같다.

 

 

옵티마이즈 옵션을 최대로 설정해 볼까? 8.9Mbps로 측정이 된다. 

 

 


RP2350의 SPI DMA를 사용해서 테스트 해볼까?

W6100의 Read/Write 함수를 DMA를 사용해서 전송 하도록 수정해서 테스트 해 보자

#ifdef USE_SPI_DMA
void wizchip_read_burst(uint8_t *pBuf, uint16_t len)
{
    uint8_t dummy_data = 0xFF;

    channel_config_set_read_increment(&dma_channel_config_tx, false);
    channel_config_set_write_increment(&dma_channel_config_tx, false);
    dma_channel_configure(dma_tx, &dma_channel_config_tx,
                          &spi_get_hw(SPI_PORT)->dr, // write address
                          &dummy_data,               // read address
                          len,                       // element count (each element is of size transfer_data_size)
                          false);                    // don't start yet

    channel_config_set_read_increment(&dma_channel_config_rx, false);
    channel_config_set_write_increment(&dma_channel_config_rx, true);
    dma_channel_configure(dma_rx, &dma_channel_config_rx,
                          pBuf,                      // write address
                          &spi_get_hw(SPI_PORT)->dr, // read address
                          len,                       // element count (each element is of size transfer_data_size)
                          false);                    // don't start yet

    dma_start_channel_mask((1u << dma_tx) | (1u << dma_rx));
    dma_channel_wait_for_finish_blocking(dma_rx);
}

void wizchip_write_burst(uint8_t *pBuf, uint16_t len)
{
    uint8_t dummy_data;

    channel_config_set_read_increment(&dma_channel_config_tx, true);
    channel_config_set_write_increment(&dma_channel_config_tx, false);
    dma_channel_configure(dma_tx, &dma_channel_config_tx,
                          &spi_get_hw(SPI_PORT)->dr, // write address
                          pBuf,                      // read address
                          len,                       // element count (each element is of size transfer_data_size)
                          false);                    // don't start yet

    channel_config_set_read_increment(&dma_channel_config_rx, false);
    channel_config_set_write_increment(&dma_channel_config_rx, false);
    dma_channel_configure(dma_rx, &dma_channel_config_rx,
                          &dummy_data,               // write address
                          &spi_get_hw(SPI_PORT)->dr, // read address
                          len,                       // element count (each element is of size transfer_data_size)
                          false);                    // don't start yet

    dma_start_channel_mask((1u << dma_tx) | (1u << dma_rx));
    dma_channel_wait_for_finish_blocking(dma_rx);
}



static uint8_t wizchip_read(void)
{
    uint8_t rx_data = 0;
    uint8_t tx_data = 0xFF;

    spi_read_blocking(SPI_PORT, tx_data, &rx_data, 1);

    return rx_data;
}

void wizchip_read_buf(uint8_t* rx_data, datasize_t len)
{
    uint8_t dummy_data = 0xFF;

    channel_config_set_read_increment(&dma_channel_config_tx, false);
    channel_config_set_write_increment(&dma_channel_config_tx, false);
    dma_channel_configure(dma_tx, &dma_channel_config_tx,
                          &spi_get_hw(SPI_PORT)->dr, // write address
                          &dummy_data,               // read address
                          len,                       // element count (each element is of size transfer_data_size)
                          false);                    // don't start yet

    channel_config_set_read_increment(&dma_channel_config_rx, false);
    channel_config_set_write_increment(&dma_channel_config_rx, true);
    dma_channel_configure(dma_rx, &dma_channel_config_rx,
                          rx_data,                      // write address
                          &spi_get_hw(SPI_PORT)->dr, // read address
                          len,                       // element count (each element is of size transfer_data_size)
                          false);                    // don't start yet

    dma_start_channel_mask((1u << dma_tx) | (1u << dma_rx));
    dma_channel_wait_for_finish_blocking(dma_rx);
}

static void wizchip_write(uint8_t tx_data)
{
    spi_write_blocking(SPI_PORT, &tx_data, 1);
}

void wizchip_write_buf(uint8_t* tx_data, datasize_t len)
{
    uint8_t dummy_data;

    channel_config_set_read_increment(&dma_channel_config_tx, true);
    channel_config_set_write_increment(&dma_channel_config_tx, false);
    dma_channel_configure(dma_tx, &dma_channel_config_tx,
                          &spi_get_hw(SPI_PORT)->dr, // write address
                          tx_data,                      // read address
                          len,                       // element count (each element is of size transfer_data_size)
                          false);                    // don't start yet

    channel_config_set_read_increment(&dma_channel_config_rx, false);
    channel_config_set_write_increment(&dma_channel_config_rx, false);
    dma_channel_configure(dma_rx, &dma_channel_config_rx,
                          &dummy_data,               // write address
                          &spi_get_hw(SPI_PORT)->dr, // read address
                          len,                       // element count (each element is of size transfer_data_size)
                          false);                    // don't start yet

    dma_start_channel_mask((1u << dma_tx) | (1u << dma_rx));
    dma_channel_wait_for_finish_blocking(dma_rx);
}

 

 

테스트 결과 SPI DMA를 사용하면 9.4Mbps 정도로 조금더 빨라지지만 비슷한 결과가 나온다.

 

 

 

iperf로 테스트 해보자

    print_network_information(g_net_info);
    while (true) {
        //loopback_tcps(SOCKET_LOOPBACK, g_loopback_buf, PORT_LOOPBACK);
        iperf_tcps(SOCKET_LOOPBACK, g_loopback_buf, PORT_LOOPBACK);
    }
}

 

 

iperf는 단방향 전송만 하기 때문에 양방향 loopback 테스트 보다 2배 정도인 18Mbps 정도로 측정이 된다.

 

 

결론

Pi Pico SDK를 사용한다면 DMA를 사용하지 않아도 옵티마니즈 많으로 충분한 성능이 나오는것 같고 Arduino 환경에서는 DMA를 사용하여 성능을 높일 수 있을것 같다.

RP2040과 W5500이 원칩으로 구성된 W55RP20의 TCP 전송률(25Mbps)와 비교해 보면 네트웍 성능면에서는 떨어지는것 같다. MCU성은이 중요 하다면 RP2350이 좋을것 같고 네트웍 성능이 필요하다면 W55RP20이 좋을것 같다.

반응형