Raspberry Pi Pico에 W5500과 W5100S를 연결한 CircuitPython 프로젝트
Raspberry Pi Pico에서 W5500과 W5100S 이더넷을 사용하기 위해 정리한 CircuitPython 예제와 WIZnet5k 드라이버 변경을 돌아봅니다.
Raspberry Pi Pico에 유선 네트워크를 붙이는 방법은 하나가 아니다. 이 프로젝트에서는 CircuitPython으로 W5500 예제를 만들고, W5100S를 지원하도록 WIZnet5k 드라이버 코드를 함께 다뤘다. 별도의 드라이버 저장소에는 socket 전송 길이를 다루는 수정도 남아 있다.
세부 코드를 최신 보드에서 그대로 실행할 수 있다고 보장하기보다는, 서로 다른 WIZnet 칩을 하나의 Python 네트워크 인터페이스에 연결할 때 어떤 경계를 살펴봐야 하는지 보여주는 기록으로 보는 편이 맞다.
두 저장소가 맡은 역할
| 저장소 | 역할 | 읽을 때 볼 부분 |
|---|---|---|
| pico-W5500 | Pico에서 W5500을 사용하는 CircuitPython 예제와 W5100S 드라이버 코드 | 보드 예제, SPI 초기화, 칩별 드라이버 처리 |
| Adafruit_CircuitPython_Wiznet5k | Adafruit WIZnet5k 드라이버를 바탕으로 한 포크 | socket_write()에서 실제 기록 길이를 사용하는 변경 |
저장소 이름은 pico-W5500이지만 README는 W5500 예제뿐 아니라 /lib/adafruit_wiznet5k 아래의 W5100S 지원 코드도 안내한다. 저장소에는 W5100S WSGI 서버, W5500 Echo, loopback, ping, MQTT 예제가 함께 있다.
CircuitPython에서 네트워크까지 이어지는 경로
전체 경로는 대략 다음과 같다.
CircuitPython 애플리케이션
|
Adafruit WIZnet5k 인터페이스와 socket API
|
SPI
|
W5500 또는 W5100S
|
Ethernet
애플리케이션은 adafruit_wiznet5k의 인터페이스와 socket 계층을 사용한다. 칩과 통신하는 물리 연결은 SPI이고, TCP/IP 처리는 WIZnet Ethernet 칩이 맡는다. 따라서 MCU에서 lwIP를 직접 구동하는 구조와는 다르다.
이 구조에서 중요한 점은 칩 이름만 바꾸면 드라이버가 자동으로 호환되는 것이 아니라는 것이다. W5500과 W5100S는 버전 레지스터, PHY 상태 레지스터, 지원 socket 수 등 칩별 차이가 있다. pico-W5500의 드라이버 코드는 W5100S용 레지스터를 별도로 정의하고 칩별 PHY 상태와 socket 수를 구분한다.
예제에서 확인할 수 있는 범위
Pico_W5500_Echo_Demo.py는 기본적인 Ethernet socket 흐름을 살펴보기에 적당하다. Pico_W5500_AX1_Loopback.py와 Pico_W5500_Ping_Test.py는 연결 확인 관점에서 볼 수 있고, Pico_W5500_MiniMQTT.py는 네트워크 연결 위에 MQTT 클라이언트를 얹는 예다. W5100S를 사용하는 WSGI 서버 예제도 별도로 들어 있다.
이 파일들은 하드웨어 연결과 API 사용 방식을 파악하는 출발점이다. 다만 예제의 존재가 오늘날의 CircuitPython 버전과 라이브러리 조합에서 동작한다는 검증을 뜻하지는 않는다.
드라이버 포크에 남은 작은 수정
별도의 WIZnet5k 드라이버 포크에는 socket_write()가 송신 버퍼에 실제로 기록한 길이 ret를 사용하도록 한 변경이 있다. 해당 변경은 송신 포인터 갱신과 버퍼 전달 길이를 요청한 전체 길이가 아니라 ret 기준으로 맞춘다.
이 수정은 API가 요청한 길이와 내부에서 처리된 길이가 달라질 수 있는 경우를 고려한 것이다. 드라이버 코드를 읽을 때는 호출자가 요청한 바이트 수, 칩에 기록한 바이트 수, 송신 포인터가 각각 어떤 값을 기준으로 움직이는지 같이 보는 것이 중요하다. 이 커밋만으로 모든 CircuitPython 버전과 WIZnet 칩 조합에서 동작한다고 단정할 수는 없다.
지금 새로 시작한다면
저장소 README는 2021년의 CircuitPython 6.x 라이브러리 번들을 안내한다. 현재 프로젝트에 그대로 복사하기보다는 CircuitPython 버전과 라이브러리 번들의 호환성을 먼저 확인하고, 드라이버 포크에만 존재하는 변경이 필요한지도 공식 Adafruit 드라이버와 비교하는 편이 안전하다.
다시 실습 자료로 정리한다면 적어도 다음을 현재 하드웨어에서 확인해야 한다.
- Pico 보드와 W5500 또는 W5100S 모듈의 SPI 핀, CS 핀 연결
- 사용하는 CircuitPython 펌웨어와
adafruit_bus_device, WIZnet5k 등 라이브러리 버전 - DHCP와 DNS 결과, socket 연결 및 송수신 동작
- W5100S와 W5500 각각에서 칩 탐지, PHY 상태, socket 수 처리
- 예제 실행 결과와 실패 시 재현 조건
이 글을 작성하면서 현재 장비로 다시 빌드하거나 네트워크 실험을 하지는 않았다. 따라서 최신 설치 절차가 아니라 저장소와 코드에 남아 있는 구조를 설명한다.
앞선 Pico 프로젝트와 구분하기
같은 Pico와 WIZnet 칩이 등장해도 앞서 살펴본 W5100S와 Azure IoT C SDK 프로젝트 회고와는 실행 환경이 다르다. 그 글은 C와 NonOS 환경에서 Azure SDK의 플랫폼 경계를 연결한 사례이고, 이 글은 CircuitPython 예제와 Python 드라이버의 칩별 처리를 다룬다. 공통점은 WIZnet 칩의 hardwired TCP/IP를 이용한다는 것이며, lwIP 포팅 자료로 혼용하면 안 된다.
정리
이 두 저장소는 Pico에서 유선 네트워크를 사용하는 과정을 예제와 드라이버 관점으로 나눠 보여준다. pico-W5500은 W5500 예제와 W5100S 드라이버 코드를 함께 볼 수 있고, 별도 포크는 socket 송신 길이를 다룬 수정 이력을 확인할 수 있다. 오래된 의존성 안내를 최신 설치법으로 받아들이기보다, 칩별 차이와 드라이버 경계를 읽는 참고 자료로 활용하는 것이 적절하다.