RP2350(pico2)によるDSP処理

RP2350(Raspberry Pi Pico 2)にFPUが搭載されているということで,浮動小数点演算による高速なDSPを期待して動作を確認してみた.開発環境はpico SDKを使うべきところかもしれないが,まずは使い慣れているArduino IDEで試してみる.

まず,追加のボードマネージャに以下のURLを追加.
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json

以下のボードマネージャをインストール

ESP32ではボードマネージャをインストールすればDSP関数もすぐ使えたが,こちらには含まれていない様子.
CMSIS-DSPライブラリを使おうと探してみると,ArduCMSIS-DSP というライブラリが見つかった.ライブラリーマネージャから検索してインストールボタンをクリックすると簡単にインストールが完了する.

早速,以下のコードでFFTの計算時間を出してみた.

#define ARM_MATH_CM33 1
#define __FPU_PRESENT 1U
#define __FPU_USED 1U

#include <Arduino.h>
#include <arm_math.h>

#include <string.h>

#define FFT_SIZE 1024
#define TEST_NUM 50

float32_t fftInput[FFT_SIZE];
float32_t fftWork[FFT_SIZE];
float32_t fftOutput[FFT_SIZE];

arm_rfft_fast_instance_f32 fft;

volatile float32_t resultCheck = 0.0f;

void setup()
{
Serial.begin(115200);
delay(2000);

Serial.println("RP2350 CMSIS-DSP FFT Benchmark");

// 入力信号を生成
for (int i = 0; i < FFT_SIZE; i++) {
fftInput[i] =
sinf(2.0f * PI * 50.0f * i / FFT_SIZE) +
0.5f * sinf(2.0f * PI * 100.0f * i / FFT_SIZE);
}

// FFT初期化
arm_status status =
arm_rfft_fast_init_f32(&fft, FFT_SIZE);

if (status != ARM_MATH_SUCCESS) {
Serial.println("FFT init error");
while (1) delay(100);
}

// ウォームアップ
for (int i = 0; i < 5; i++) {
memcpy(fftWork, fftInput, sizeof(fftInput));
arm_rfft_fast_f32(
&fft, fftWork, fftOutput, 0);
}

// ---------------------------------
// 1. FFT + 入力コピーの時間
// ---------------------------------
uint32_t t1 = micros();

for (int i = 0; i < TEST_NUM; i++) {

memcpy(fftWork, fftInput, sizeof(fftInput));

arm_rfft_fast_f32(
&fft, fftWork, fftOutput, 0);
}

uint32_t t2 = micros();

resultCheck = fftOutput[10] + fftOutput[20];

float totalTime =
(float)(t2 - t1) / TEST_NUM;

// ---------------------------------
// 2. 入力コピーだけの時間
// ---------------------------------
t1 = micros();

for (int i = 0; i < TEST_NUM; i++) {
memcpy(fftWork, fftInput, sizeof(fftInput));
resultCheck += fftWork[i];
}

t2 = micros();

float copyTime =
(float)(t2 - t1) / TEST_NUM;

// ---------------------------------
// 3. FFT本体の推定時間
// ---------------------------------
float fftTime = totalTime - copyTime;

Serial.println("------------------------");

Serial.print("Total : ");
Serial.print(totalTime, 2);
Serial.println(" us");

Serial.print("Copy : ");
Serial.print(copyTime, 2);
Serial.println(" us");

Serial.print("FFT estimate: ");
Serial.print(fftTime, 2);
Serial.println(" us");

Serial.println("------------------------");
}

void loop()
{
}

その結果,

1024点FFTに18msもかかっていて使い物にならない.

ソースコードをどう弄ってもダメなので,ライブラリの中身を確認することにした.
ライブラリで提供されているのは,ヘッダファイルと
libraries\ArduCMSIS-DSP\src\cortex-m33\libCMSISDSP.a
というライブラリファイル一つ.

libCMSISDSP.a を逆アセンブルしてみると,FPUをまったく使っていないことがわかった.ライブラリのビルド時にFPUを使う設定になっていなかったのだろう.どおりで何をやっても変わらないわけだ.

ここですんなり諦めて pico SDK に移行しようかと思ったが,Arduino IDE で環境を作っておきたかったので,何とかしてみることにした.いろいろ検討した結果,自前で libCMSISDSP.a を作って入れ替えることにした.

CMSIS のソースコードがないので https://github.com/ARM-software/CMSIS_5 ここから取得.
結果できたファイルがこちら libCMSISDSP.zip

libraries\ArduCMSIS-DSP\src\cortex-m33\libCMSISDSP.a と入れ替えてもう一度テストプログラムを実行.

およそ0.47msで約40倍高速になった.これはCPUクロックが標準の150MHz の場合だが,
ESP32-S3 と同じ 240MHzにオーバークロックしてみると,

およそ0.29ms となった.これはESP32-S3とほぼ同等の性能と思われる.
RP2350もデュアルコアなので,ESP32-S3と同等のパフォーマンスが期待できそう.
Wifi不要ならチップの値段が安いRP2350を使うのがよいかも.

コメントをどうぞ