From e429ef1cc0d987b25235e77819771d4532dd4306 Mon Sep 17 00:00:00 2001 From: FallenSigh Date: Sun, 12 Apr 2026 22:28:01 +0800 Subject: [PATCH] test(fft): add C example to verify FFT IP --- sdk/software/examples/fft/Makefile | 11 ++ sdk/software/examples/fft/main.c | 178 +++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 sdk/software/examples/fft/Makefile create mode 100644 sdk/software/examples/fft/main.c diff --git a/sdk/software/examples/fft/Makefile b/sdk/software/examples/fft/Makefile new file mode 100644 index 0000000..75d724f --- /dev/null +++ b/sdk/software/examples/fft/Makefile @@ -0,0 +1,11 @@ +TARGET = fft + +CFLAGS += -O3 -g + +C_SRCS := $(wildcard ./*.c ) + +OBJDIR = obj +COMMON_DIR = ../../bsp +GCC_DIR=../../../toolchains/loongson-gnu-toolchain-8.3-x86_64-loongarch32r-linux-gnusf-v2.0 +PICOLIBC_DIR=../../../toolchains/picolibc +include ../../bsp/common.mk diff --git a/sdk/software/examples/fft/main.c b/sdk/software/examples/fft/main.c new file mode 100644 index 0000000..927e9f3 --- /dev/null +++ b/sdk/software/examples/fft/main.c @@ -0,0 +1,178 @@ +#include +#include +#include +#include +#include + +// BSP板级支持包所需全局变量 +unsigned long UART_BASE = 0xbf000000; +unsigned long CONFREG_TIMER_BASE = 0xbf20f100; +unsigned long CONFREG_CLOCKS_PER_SEC = 50000000L; +unsigned long CORE_CLOCKS_PER_SEC = 33000000L; + +#define FFT_BASE 0xbf400000 +#define FFT_IN_RE_BASE (FFT_BASE + 0x1000) +#define FFT_IN_IM_BASE (FFT_BASE + 0x2000) +#define FFT_OUT_RE_BASE (FFT_BASE + 0x3000) +#define FFT_OUT_IM_BASE (FFT_BASE + 0x4000) +#define FFT_CSR_REG (FFT_BASE + 0xF000) +#define FFT_CTRL_START (1 << 4) +#define FFT_STAT_DONE (1 << 1) +#define FFT_STAT_BUSY (1 << 0) +#define FFT_POINT_NUM 1024 + +#define DMA_BASE 0xbf300000 +#define DMA_CTRL (DMA_BASE + 0x0000) +#define DMA_LEN (DMA_BASE + 0x0004) +#define DMA_SRC_ADDR (DMA_BASE + 0x0008) +#define DMA_DST_ADDR (DMA_BASE + 0x000c) +#define DMA_STATUS (DMA_BASE + 0x0010) + +const float PI = 3.14159265358979323846; + +// 读取定时器的当前Tick +unsigned int get_timer_ticks() { + return RegRead(CONFREG_TIMER_BASE); +} + +// --------------------------------------------------------- +// 软件FFT实现 (基2 DIT-FFT 算法) +// --------------------------------------------------------- +void sw_fft(float re[], float im[], int n) { + int i, j, k, l; + float tr, ti, ur, ui, wr, wi; + + // 1. 比特翻转 (Bit Reversal) + j = 0; + for (i = 0; i < n - 1; i++) { + if (i < j) { + tr = re[i]; ti = im[i]; + re[i] = re[j]; im[i] = im[j]; + re[j] = tr; im[j] = ti; + } + k = n / 2; + while (k <= j) { + j -= k; + k /= 2; + } + j += k; + } + + // 2. 蝶形运算 (Butterfly Computation) + for (l = 1; l < n; l *= 2) { + ur = 1.0; + ui = 0.0; + wr = cos(PI / l); + wi = -sin(PI / l); + + for (i = 0; i < n; i += 2 * l) { + ur = 1.0; + ui = 0.0; + for (j = 0; j < l; j++) { + int p = i + j; + int q = p + l; + + tr = re[q] * ur - im[q] * ui; + ti = re[q] * ui + im[q] * ur; + + re[q] = re[p] - tr; + im[q] = im[p] - ti; + re[p] += tr; + im[p] += ti; + + float next_ur = ur * wr - ui * wi; + ui = ur * wi + ui * wr; + ur = next_ur; + } + } + } +} + +int main(int argc, char** argv) +{ + unsigned int fft_csr = RegRead(FFT_CSR_REG); + printf("fft_csr = %x\n", fft_csr); + + // 准备测试数据 + float sw_in_re[FFT_POINT_NUM]; + float sw_in_im[FFT_POINT_NUM]; + + for (int i = 0; i < FFT_POINT_NUM; i++) { + float dc_part = 4000.0f; + float f10_part = 8000.0f * cos(2 * PI * 10.0 * i / FFT_POINT_NUM); + float f200_part = 6000.0f * sin(2 * PI * 200.0 * i / FFT_POINT_NUM); + float f400_part = 3000.0f * sin(2 * PI * 400.0 * i / FFT_POINT_NUM); + + sw_in_re[i] = dc_part + f10_part + f200_part + f400_part; + sw_in_im[i] = 0.0f; + } + + unsigned int tick_start, tick_end; + unsigned int hw_time, sw_time; + + // ========================================== + // 1. 硬件加速 FFT 测试 + // ========================================== + printf("\n--- Starting Hardware FFT ---\n"); + tick_start = get_ns(); + + for (int i = 0; i < FFT_POINT_NUM; i++) { + RegWrite(FFT_IN_RE_BASE + (i * 4), (unsigned int)((int)sw_in_re[i])); + RegWrite(FFT_IN_IM_BASE + (i * 4), 0); + } + + + RegWrite(FFT_CSR_REG, FFT_CTRL_START); + while ((RegRead(FFT_CSR_REG) & FFT_STAT_DONE) == 0) { + // 等待硬件计算完成 + } + + tick_end = get_ns(); + + // 如果定时器是递减的,这里可能是 tick_start - tick_end + // 假设定时器是向上递增的: + hw_time = tick_end - tick_start; + + int hw_out_re[FFT_POINT_NUM]; + int hw_out_im[FFT_POINT_NUM]; + for (int i = 0; i < FFT_POINT_NUM; i++) { + hw_out_re[i] = (int)RegRead(FFT_OUT_RE_BASE + (i * 4)); + hw_out_im[i] = (int)RegRead(FFT_OUT_IM_BASE + (i * 4)); + } + + // ========================================== + // 2. 纯软件 FFT 测试 + // ========================================== + printf("--- Starting Software FFT ---\n"); + tick_start = get_ns(); + + sw_fft(sw_in_re, sw_in_im, FFT_POINT_NUM); + + tick_end = get_ns(); + sw_time = tick_end - tick_start; + + + // ========================================== + // 3. 打印对比结果 + // ========================================== + printf("\n--- Performance Comparison ---\n"); + printf("Timer Clock Freq : %lu Hz\n", CONFREG_CLOCKS_PER_SEC); + printf("Hardware FFT Time: %u ns (%.3f ms)\n", hw_time, (float)hw_time / 1000000.0); + printf("Software FFT Time: %u ns (%.3f ms)\n", sw_time, (float)sw_time / 1000000.0); + + if (hw_time > 0) { + printf("Speedup Ratio : %.2fx\n", (float)sw_time / hw_time); + } + + printf("\n--- Verification (Only showing Bins with energy > 10) ---\n"); + for (int i = 0; i < FFT_POINT_NUM; i++) { + if (fabs(hw_out_re[i]) > 10 || fabs(hw_out_im[i]) > 10) { + printf("Bin [%4d] Hz: HW(Re:%6d, Im:%6d) | SW(Re:%6d, Im:%6d)\n", + i, + hw_out_re[i], hw_out_im[i], + (int)sw_in_re[i] / FFT_POINT_NUM, (int)sw_in_im[i] / FFT_POINT_NUM); + } + } + + return 0; +} \ No newline at end of file