test(fft): update fft_dma example

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-07-05 23:25:51 +08:00
parent 088a9bd5b8
commit 34ce639f69
2 changed files with 21 additions and 7 deletions

View File

@@ -10,6 +10,7 @@
#define FFT_STAT_DONE (1 << 1) #define FFT_STAT_DONE (1 << 1)
#define FFT_STAT_BUSY (1 << 0) #define FFT_STAT_BUSY (1 << 0)
#define FFT_POINT_NUM 1024 #define FFT_POINT_NUM 1024
#define FFT_SAMPLE_BITS 16
void fft_start(); void fft_start();
void fft_wait(); void fft_wait();

View File

@@ -67,7 +67,8 @@ void sw_fft(float re[], float im[], int n) {
} }
} }
// 全局对齐数组:作为 DMA 的源和目的内存 // 全局对齐数组:作为 DMA 的源和目的内存。
// FFT 外设仍按 32-bit AXI word 编址,每个 word 的低 16 bit 作为一个 signed 样本。
int32_t hw_in_re_arr[FFT_POINT_NUM] __attribute__((aligned(64))); int32_t hw_in_re_arr[FFT_POINT_NUM] __attribute__((aligned(64)));
int32_t hw_in_im_arr[FFT_POINT_NUM] __attribute__((aligned(64))); int32_t hw_in_im_arr[FFT_POINT_NUM] __attribute__((aligned(64)));
int32_t hw_out_re_arr[FFT_POINT_NUM] __attribute__((aligned(64))); int32_t hw_out_re_arr[FFT_POINT_NUM] __attribute__((aligned(64)));
@@ -95,13 +96,13 @@ int main(int argc, char** argv)
float sw_in_im[FFT_POINT_NUM]; float sw_in_im[FFT_POINT_NUM];
for (int i = 0; i < FFT_POINT_NUM; i++) { for (int i = 0; i < FFT_POINT_NUM; i++) {
int32_t sample = fft_test_sample((unsigned int)i); int16_t sample = (int16_t)fft_test_sample((unsigned int)i);
sw_in_re[i] = (float)sample; sw_in_re[i] = (float)sample;
sw_in_im[i] = 0.0f; sw_in_im[i] = 0.0f;
// 硬件输入需要转为整数存入无缓存内存 // 硬件输入为 16-bit signed,写入 32-bit word 的低半字。
uncached_in_re[i] = sample; uncached_in_re[i] = (int32_t)sample;
uncached_in_im[i] = 0; uncached_in_im[i] = 0;
// 清理输出内存以防干扰 // 清理输出内存以防干扰
@@ -116,7 +117,7 @@ int main(int argc, char** argv)
printf("\n--- Starting Hardware FFT with DMA ---\n"); printf("\n--- Starting Hardware FFT with DMA ---\n");
tick_start = get_ns(); // 开始计时 tick_start = get_ns(); // 开始计时
uint32_t transfer_bytes = FFT_POINT_NUM * 4; // 1024个点 * 4字节 uint32_t transfer_bytes = FFT_POINT_NUM * 4; // 1024个点 * 4字节,低16位有效
// MA 将数据从内存搬运到 FFT 输入外设 // MA 将数据从内存搬运到 FFT 输入外设
dma_start_transfer(0, ((uint32_t)hw_in_re_arr & 0x1FFFFFFF), phys_fft_in_re, transfer_bytes, 100); dma_start_transfer(0, ((uint32_t)hw_in_re_arr & 0x1FFFFFFF), phys_fft_in_re, transfer_bytes, 100);
@@ -158,19 +159,31 @@ int main(int argc, char** argv)
printf("Speedup Ratio : %.2fx\n", (float)sw_time / hw_time); printf("Speedup Ratio : %.2fx\n", (float)sw_time / hw_time);
} }
printf("\n--- Verification (Only showing Bins with energy > 10) ---\n"); printf("\n--- Verification (%d-bit FFT, only showing bins with energy > 10) ---\n", FFT_SAMPLE_BITS);
int max_abs_err_re = 0;
int max_abs_err_im = 0;
for (int i = 0; i < FFT_POINT_NUM; i++) { for (int i = 0; i < FFT_POINT_NUM; i++) {
// CPU 通过无缓存指针读取 DMA 搬运回来的结果 // CPU 通过无缓存指针读取 DMA 搬运回来的结果
int32_t hw_re = uncached_out_re[i]; int32_t hw_re = uncached_out_re[i];
int32_t hw_im = uncached_out_im[i]; int32_t hw_im = uncached_out_im[i];
int32_t sw_re = (int32_t)sw_in_re[i] / FFT_POINT_NUM;
int32_t sw_im = (int32_t)sw_in_im[i] / FFT_POINT_NUM;
int err_re = (int)(hw_re - sw_re);
int err_im = (int)(hw_im - sw_im);
if (err_re < 0) err_re = -err_re;
if (err_im < 0) err_im = -err_im;
if (err_re > max_abs_err_re) max_abs_err_re = err_re;
if (err_im > max_abs_err_im) max_abs_err_im = err_im;
if (fabs((float)hw_re) > 10 || fabs((float)hw_im) > 10) { if (fabs((float)hw_re) > 10 || fabs((float)hw_im) > 10) {
printf("Bin [%4d] Hz: HW(Re:%6d, Im:%6d) | SW(Re:%6d, Im:%6d)\n", printf("Bin [%4d] Hz: HW(Re:%6d, Im:%6d) | SW(Re:%6d, Im:%6d)\n",
i, i,
hw_re, hw_im, hw_re, hw_im,
(int)sw_in_re[i] / FFT_POINT_NUM, (int)sw_in_im[i] / FFT_POINT_NUM); sw_re, sw_im);
} }
} }
printf("Max Abs Error : Re=%d, Im=%d\n", max_abs_err_re, max_abs_err_im);
return 0; return 0;
} }