[STM32-64 Ardu] STM32F405에서 W5500 DHCP 테스트 예제를 이용하여 iperf로 W5500의 네트웍 전송율 테스트를 해 보자
우선 W5500 Arduino 라이브러리 파일에서 클럭 속도를 최대치로 설정 한다.
\Arduino\libraries\Ethernet2\src\utility\w5500.cpp
SPISettings wiznet_SPI_settings(42000000, MSBFIRST, SPI_MODE0);
Arduino 에서 iperf 를 이용한 네트웍 전송율 테스트를 하기 위해 TCP Server를 구현 하면 된다.
#include <SPI.h>
#include <Ethernet2.h>
#define USE_THIS_SS_PIN PB0
byte mac[] = {0x00, 0x08, 0xDC, 0x00, 0x00, 0x00};
EthernetServer server(5001);
void setup() {
Serial.begin(115200);
Serial.print("Iperf server address : ");
Ethernet.w5500_cspin = USE_THIS_SS_PIN;
// initialize the ethernet device
Ethernet.begin(mac);
// start listening for clients
server.begin();
Serial.println(Ethernet.localIP());
Serial.println(" ");
}
void loop() {
byte buf[2048];
unsigned int len = 0;
// wait for a new client:
EthernetClient client = server.available();
if (client) {
while (client.connected())
{
len = client.available();
if (len)
{
client.read(buf, 2048);
}
}
// close the connection:
client.stop();
Serial.println("client disonnected");
}
}
STM32F4 에서 Arduino코드로 W5500의 TCP 전송 속도는 4.5Mbps 정도로 측정된다.
iperf -c 192.168.1.48 -w 300k -t 100 -i 10
STM32CubeIDE에서 Iperf로 W5500의 TCP Throughput 측정 테스트 결과 30Mbps와 비교하면 너무 많은 속도 차이가 발생한다.
무엇이 문제 일까?
Arduino는 다양한 MCU를 지원하기 위해 표준 함수를 사용하다보니 효율성이 떨어지는것 같다.
W5500 Arduino 라이브러리 Ethernet2 의 w5500.cpp에서 read, write 함수를 보니 SPI 통신을 한바이트씩 수행하고 있다.
이것 때문에 속도가 느려진것 같다.
uint16_t W5500Class::write(uint16_t _addr, uint8_t _cb, const uint8_t *_buf, uint16_t _len)
{
SPI.beginTransaction(wiznet_SPI_settings);
setSS();
SPI.transfer(_addr >> 8);
SPI.transfer(_addr & 0xFF);
SPI.transfer(_cb);
for (uint16_t i=0; i<_len; i++){
SPI.transfer(_buf[i]);
}
resetSS();
SPI.endTransaction();
return _len;
}
uint16_t W5500Class::read(uint16_t _addr, uint8_t _cb, uint8_t *_buf, uint16_t _len)
{
SPI.beginTransaction(wiznet_SPI_settings);
setSS();
SPI.transfer(_addr >> 8);
SPI.transfer(_addr & 0xFF);
SPI.transfer(_cb);
for (uint16_t i=0; i<_len; i++){
_buf[i] = SPI.transfer(0);
}
resetSS();
SPI.endTransaction();
return _len;
}
Arduino에서 SPI 데이터를 한바이트씩 전송하면 지연시간이 상당히 긴데 고속전송에서는 문제가 발생한다.
이 부분을 Burst모드로 전송할 수 있도록 코드를 수정 했다. Arduino 에서 제공하는 SPI 클래스를 사용하지 않고 별도의 SPI 클래스를 만들어서 구현 하였다.
uint16_t W5500Class::write(uint16_t _addr, uint8_t _cb, const uint8_t *_buf, uint16_t _len)
{
spi_data[0] = (_addr & 0x0000FF00) >> 8;
spi_data[1] = (_addr & 0x000000FF) >> 0;
spi_data[2] = _cb;
spi_write_buf(spi_data, 3);
spi_write_buf((uint8_t *)_buf, _len);
resetSS();
return _len;
}
uint16_t W5500Class::read(uint16_t _addr, uint8_t _cb, uint8_t *_buf, uint16_t _len)
{
spi_data[0] = (_addr & 0x0000FF00) >> 8;
spi_data[1] = (_addr & 0x000000FF) >> 0;
spi_data[2] = _cb;
spi_write_buf(spi_data, 3);
spi_read_buf(_buf, _len);
resetSS();
return _len;
}
이렇게 수정후 테스트 결과 STM32F405 Arduio에서 W5500의 iperf TCP Throughput 측정 테스트결과 9Mbps가 측정된다.
spi_write_buf(), spi_read_buf() 함수를 DMA로 변경 하니 속도가 두배 정도 더 빨라진다.
다만 DMA의 경우 Arduino에서 구현 하기에 어려움이 많은데 이렇게 되면 다른 MCU와 호환하는데 문제가 발생할 수 있다.
STM32F405 STM32CubeIDE 에서 W5500 iperf 전송율 테스트 속도보다는 느리지만 Arduino 환경의 다양한 어플리케이션을 쉽게 적용할 수 있는 장점으로 본다면 나쁘지 않은것 같다.