---
title: "RP2040 + W5100S Multicore Basic"
url: "https://maker.wiznet.io/jaden/projects/rp2040-w5100s-multicore-basic/"
markdown_url: "https://maker.wiznet.io/jaden/projects/rp2040-w5100s-multicore-basic/md"
type: "WCC: WIZnet Created Content"
author: "jaden kim"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "jaden kim"
published: "2023-08-21"
language: "en"
hardware: ["WIZnet W5100S-EVB-Pico"]
likes: 1
views: 2401
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# RP2040 + W5100S Multicore Basic

> RP2040 Multicore basic with W5100s

Original author: jaden kim

## Components

- **WIZnet W5100S-EVB-Pico** x 1 ([docs](https://docs.wiznet.io/Product/Chip/Ethernet/W5100S/w5100s-evb-pico))

## Documents and links

- [Multicore_example](https://github.com/wiznetmaker/Multicore_example) (code): RP2040 Multicore_example with W5100S

## Article

Hello!

Today, I will explain a project where we use both cores of the RP2040 mounted on the W5100S-EVB-PICO to read ADC data and send this data to a connected TCP client!

![](https://maker.wiznet.io/upload/ckeditor5/836767397%5F1692376866%2Epng)

The Raspberry Pi RP2040 used in the W5100S-EVB-PICO has two cores (M0+).

![](https://maker.wiznet.io/upload/ckeditor5/836767397%5F1692376908%2Epng)![](https://maker.wiznet.io/upload/ckeditor5/836767397%5F1692376983%2Epng)

If you have used the W5100S-EVB-PICO, you will know that Wiznet provides [**basic sample codes**](https://github.com/Wiznet/RP2040-HAT-C).

The examples are all single-core implementations, and to better utilize the hardware resources of the RP2040, it's more efficient to implement using multi-cores.

However, many of the RP2040 multi-core examples available online are implemented in MicroPython.

While these examples make multi-core implementation easier, they don't align with the ultimate goal of this project: to efficiently use limited embedded hardware resources. Hence, we used the C language for this project.

The following sections will explain the necessary hardware connections and software settings for operating the project.

![](https://maker.wiznet.io/upload/ckeditor5/190643059%5F1692614078%2Epng)

*HW connection*

You can use the RPI-PICO and the W5100S module for hardware, but I used the W5100S-EVB-PICO EVB that includes both the RP2040 and W5100S.

For ADC input, you can use a variable resistor, but I used an XY-Joystick for future projects. The XY-Joystick module I used can output ADC values for both the X and Y axes, but this project only takes one ADC input.

The ADC input is fed into GP26 (ADC0).

The W5100S is mounted on the W5100S-EVB-PICO and is set to SPI0 (MOSI - GP19, MISO - GP16, SCK - SP18, CS - GP17, INT - GP21, RST - GP20).

For multi-core implementation, I referred to the [**pico_multicore section from the PICO-SDK documentation**](https://www.raspberrypi.com/documentation/pico-sdk/high_level.html#pico_multicore) provided by Rpi.

Below is the main code for the project.

#include "hardware/adc.h"

#include "hardware/timer.h"

#include "hardware/sync.h"

#include &lt;stdio.h>

#include "port_common.h"

#include "wizchip_conf.h"

#include "w5x00_spi.h"

#include "socket.h"

#include "pico/multicore.h"

#define TIMER_PERIOD_MS (1000)

#define PLL_SYS_KHZ (133 * 1000)

#define ETHERNET_BUF_MAX_SIZE (1024 * 2)

#define SOCKET_LOOPBACK 0

#define PORT 5000

#define ADC0_PIN 26

static wiz_NetInfo g_net_info = {

.mac = {0x00, 0x08, 0xDC, 0x12, 0x34, 0x56},

.ip = {192, 168, 11, 2},

.sn = {255, 255, 255, 0},

.gw = {192, 168, 11, 1},

.dns = {8, 8, 8, 8},

.dhcp = NETINFO_STATIC

};

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

// 기존 함수와 중복되지 않도록 함수명을 변경하였습니다.

static void init_clock_khz(void) {

set_sys_clock_khz(PLL_SYS_KHZ, true);

clock_configure(

clk_peri,

0,

CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,

PLL_SYS_KHZ * 1000,

PLL_SYS_KHZ * 1000

);

}

static void read_adc_core1() {

while (true) {

adc_select_input(0);

uint16_t result = adc_read();

multicore_fifo_push_blocking(result);

sleep_ms(TIMER_PERIOD_MS);

}

}

static int32_t send_adc_data_to_client(uint8_t sn, uint8_t* buf, uint16_t port) {

uint16_t adc_value = multicore_fifo_pop_blocking();

sprintf((char*)buf, "ADC data : %d\n", adc_value);

int32_t ret;

switch(getSn_SR(sn)) {

case SOCK_ESTABLISHED:

if(getSn_IR(sn) & Sn_IR_CON) {

setSn_IR(sn, Sn_IR_CON);

printf("Client connected!\n");

}

if ((ret = send(sn, buf, strlen((char*)buf))) &lt;= 0) {

return ret;

}

break;

case SOCK_CLOSE_WAIT:

if ((ret = disconnect(sn)) != SOCK_OK) {

return ret;

}

break;

case SOCK_INIT:

if ((ret = listen(sn)) != SOCK_OK) {

return ret;

}

printf("Waiting client connection...\n");

break;

case SOCK_CLOSED:

if ((ret = socket(sn, Sn_MR_TCP, port, 0x00)) != sn) {

return ret;

}

break;

default:

break;

}

return 1;

}

int main() {

int retval = 0;

init_clock_khz();

stdio_init_all();

wizchip_spi_initialize();

wizchip_cris_initialize();

wizchip_reset();

wizchip_initialize();

wizchip_check();

network_initialize(g_net_info);

adc_init();

adc_gpio_init(ADC0_PIN);

multicore_launch_core1(read_adc_core1);

print_network_information(g_net_info);

printf("Port : %d\n", PORT); // 포트 번호 출력 부분 추가

while (1) {

if ((retval = send_adc_data_to_client(SOCKET_LOOPBACK, Send_buf, PORT)) &lt; 0) {

printf(" Data sending error : %d\n", retval);

while (1);

}

}

}

Flow of the main function:

System clock initialization: Call the init_clock_khz function.
Initialize standard I/O: Call the stdio_init_all function.
Wiznet W5100S initialization: Initialize W5100S using wizchip functions.
Network setting: Configure the network using g_net_info.
ADC initialization: Initialize the ADC and ADC pins.
Run Core1: Start reading the ADC value in Core1 using the read_adc_core1 function.
Print network information: Display the current network configuration information.
Infinite loop: Periodically send ADC data to the TCP client using the send_adc_data_to_client function.
The complete source code is posted on a Github link, so please refer to it.

Here is a video of the project in operation.

For the TCP client, we used herculas.exe

![](https://maker.wiznet.io/upload/ckeditor5/190643692%5F1692627282%2Egif)

In future projects, we will use this project as a basis to explore various multi-core projects.

Thank you for reading this long post.

---

안녕하세요!

오늘은 W5100S-EVB-PICO에 실장된 RP2040의 두개의 core를 활용하여 ADC 데이터를 읽고 해당 데이터를 연결된 TCP client에 전송하는 프로젝트에 대해 설명 드리겠습니다!

![](https://maker.wiznet.io/upload/ckeditor5/836767397%5F1692376866%2Epng)

W5100S-EVB-PICO에 사용된 라즈베리파이 RP2040에는 2개의 Core(M0+)가 있습니다.

![](https://maker.wiznet.io/upload/ckeditor5/836767397%5F1692376908%2Epng)![](https://maker.wiznet.io/upload/ckeditor5/836767397%5F1692376983%2Epng)

W5100S-EVB-PICO를 사용해보신 분들이라면 Wiznet에서 [기본 예제](https://github.com/Wiznet/RP2040-HAT-C)들을 제공한다는 사실을 알고계실겁니다.

해당 예제들은 모두 싱글코어로 구현된 예제들이고, RP2040의 HW 리소스를 좀 더 활용하기 위해서는 멀티코어를 활용하여 구현하는게 효율적입니다.

하지만 많은 웹상의 많은 RP2040 멀티코어 예제들이 MicroPython으로 구현되어있습니다.

해당 예제들을 사용한다면 Multi-Core를 구현하기 수월하겠지만, 이 프로젝트의 궁극적인 목표인 한정된 임베디드 HW 리소스를 효율적으로 사용하는 목표에는 적합하지 않습니다. 그렇기 때문에 본 프로젝트에서는 **C 언어**를 사용하였습니다.

아래 글 부터는 프로젝트를 구동하는데 필요한 HW 연결과 SW 세팅을 설명 드리겠습니다.

![](https://maker.wiznet.io/upload/ckeditor5/190643059%5F1692614078%2Epng)

*HW connection*

HW는 RPI-PICO와 W5100S 모듈을 사용하셔도 되지만, 저는 RP2040과 W5100S가 포함된 EVB인 W5100S-EVB-PICO를 사용하였습니다.

ADC 입력은 가변저항을 사용해도 되지만, 추후에 다른 프로젝트에 사용하기 위해 XY-Joystick을 사용했습니다. 사용한 XY-Joystick 모듈은 X축과 Y축 ADC 값을 2개 출력 가능하지만 본 프로젝트에서는 1개의 ADC만 입력으로 받았습니다.

ADC 입력은 GP26번 (ADC0)로 입력됩니다.

W5100S는 W5100S-EVB-PICO에 실장되어있고 SPI0(MOSI - GP19, MISO - GP16, SCK - SP18, CS - GP17, INT - GP21, RST - GP20)으로 세팅하였습니다.

Multi-Core 구현을 위해 Rpi에서 제공하는 PICO-SDK 문서중 [pico_multicore](https://www.raspberrypi.com/documentation/pico-sdk/high_level.html#pico_multicore)를 참고했습니다.

아래는 프로젝트의 Main에 해당하는 코드입니다.

#include "hardware/adc.h"

#include "hardware/timer.h"

#include "hardware/sync.h"

#include &lt;stdio.h>

#include "port_common.h"

#include "wizchip_conf.h"

#include "w5x00_spi.h"

#include "socket.h"

#include "pico/multicore.h"

#define TIMER_PERIOD_MS (1000)

#define PLL_SYS_KHZ (133 * 1000)

#define ETHERNET_BUF_MAX_SIZE (1024 * 2)

#define SOCKET_LOOPBACK 0

#define PORT 5000

#define ADC0_PIN 26

static wiz_NetInfo g_net_info = {

.mac = {0x00, 0x08, 0xDC, 0x12, 0x34, 0x56},

.ip = {192, 168, 11, 2},

.sn = {255, 255, 255, 0},

.gw = {192, 168, 11, 1},

.dns = {8, 8, 8, 8},

.dhcp = NETINFO_STATIC

};

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

// 기존 함수와 중복되지 않도록 함수명을 변경하였습니다.

static void init_clock_khz(void) {

set_sys_clock_khz(PLL_SYS_KHZ, true);

clock_configure(

clk_peri,

0,

CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,

PLL_SYS_KHZ * 1000,

PLL_SYS_KHZ * 1000

);

}

static void read_adc_core1() {

while (true) {

adc_select_input(0);

uint16_t result = adc_read();

multicore_fifo_push_blocking(result);

sleep_ms(TIMER_PERIOD_MS);

}

}

static int32_t send_adc_data_to_client(uint8_t sn, uint8_t* buf, uint16_t port) {

uint16_t adc_value = multicore_fifo_pop_blocking();

sprintf((char*)buf, "ADC data : %d\n", adc_value);

int32_t ret;

switch(getSn_SR(sn)) {

case SOCK_ESTABLISHED:

if(getSn_IR(sn) & Sn_IR_CON) {

setSn_IR(sn, Sn_IR_CON);

printf("Client connected!\n");

}

if ((ret = send(sn, buf, strlen((char*)buf))) &lt;= 0) {

return ret;

}

break;

case SOCK_CLOSE_WAIT:

if ((ret = disconnect(sn)) != SOCK_OK) {

return ret;

}

break;

case SOCK_INIT:

if ((ret = listen(sn)) != SOCK_OK) {

return ret;

}

printf("Waiting client connection...\n");

break;

case SOCK_CLOSED:

if ((ret = socket(sn, Sn_MR_TCP, port, 0x00)) != sn) {

return ret;

}

break;

default:

break;

}

return 1;

}

int main() {

int retval = 0;

init_clock_khz();

stdio_init_all();

wizchip_spi_initialize();

wizchip_cris_initialize();

wizchip_reset();

wizchip_initialize();

wizchip_check();

network_initialize(g_net_info);

adc_init();

adc_gpio_init(ADC0_PIN);

multicore_launch_core1(read_adc_core1);

print_network_information(g_net_info);

printf("Port : %d\n", PORT); // 포트 번호 출력 부분 추가

while (1) {

if ((retval = send_adc_data_to_client(SOCKET_LOOPBACK, Send_buf, PORT)) &lt; 0) {

printf(" Data sending error : %d\n", retval);

while (1);

}

}

}

간략하게 설명드리면 아래와 같습니다.

init_clock_khz: 시스템 클럭 설정 함수입니다. 클럭의 소스 및 주파수를 설정합니다.

read_adc_core1: Core1에서 동작할 함수입니다. ADC 값을 주기적으로 읽고, 읽은 값을 FIFO를 통해 Core0에 전송합니다.

send_adc_data_to_client: Core0에서 동작하는 함수로, Core1에서 읽은 ADC 값을 가져와서 TCP 클라이언트에 전송합니다. 소켓의 상태에 따라 연결 및 데이터 전송을 관리합니다.

메인 함수의 흐름:

시스템 클럭 초기화: init_clock_khz 함수 호출
표준 입출력 초기화: stdio_init_all 함수 호출
Wiznet W5100S 초기화: wizchip 관련 함수들로 W5100S 초기화
네트워크 설정: g_net_info를 사용하여 네트워크 설정
ADC 초기화: ADC 및 ADC 핀 초기화
Core1 실행: Core1에서 read_adc_core1 함수를 실행하여 ADC 값을 읽기 시작
네트워크 정보 출력: 현재 네트워크 설정 정보를 출력
무한 루프: send_adc_data_to_client 함수를 통해 ADC 데이터를 TCP 클라이언트에게 주기적으로 전송

전체 소스코드는 [Github link](https://github.com/wiznetmaker/Multicore_example)에 올려두었으니 참고 바랍니다.

해당 프로젝트의 구동 영상입니다.

TCP client는 herculas.exe 를 사용하였습니다.

![](https://maker.wiznet.io/upload/ckeditor5/190643692%5F1692627282%2Egif)

이후에 진행하는 프로젝트에는 본 프로젝트를 활용하여 다양한 멀티코어 프로젝트를 진행해 보겠습니다.

긴 글 읽어주셔서 감사합니다.

---

Source: https://maker.wiznet.io/jaden/projects/rp2040-w5100s-multicore-basic/
