Skip to content

Concepts First

  • DSP library: a set of optimized math functions (filtering, FFT, matrices, trigonometry) that are faster than hand-written loops — the foundation of signal processing.
  • Q15/Q31 fixed point: embedded systems often avoid floating point, representing fractions with 16/32-bit integers; q31 means the 1.31 fixed-point format.
  • FIR filter: finite impulse response filter; the output is a weighted sum of recent inputs, widely used for denoising and shaping.
  • FFT (Fast Fourier Transform): converts a time-domain signal to the frequency domain; rfft is the real-input variant for spectrum analysis.
  • Reference comparison: each case has a precomputed ref_result array and only prints success when outputs match, proving the algorithm implementation is correct.

Example Overview

This page is based on the dsp example in the official Bouffalo SDK (examples/dsp), which demonstrates the RISC-V DSP math library (csi_math):

  • main.c compiles the 5 case files under cases/ into one binary using a macro-rename trick and calls them in sequence;
  • Each case computes from the src input array and compares point by point against ref_result; a mismatch prints failure and halts;
  • Covers 5 typical algorithms: FIR filtering, matrix multiply, real FFT, sine, variance;
  • When all pass it prints Example all successfully! and enters a dead loop.
  • Typical uses: audio equalization/denoising (FIR), vibration spectrum analysis (FFT), sensor calibration (matrix/variance).

Note

BL616/BL618 RISC-V cores support DSP extension instructions, which the SDK's csi_math library uses automatically — this page validates that hardware-accelerated math path.

Operation Steps

1
Enter the Example Directory

Open a terminal and enter the SDK DSP example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):

cd examples/dsp
2
Build the Project

Run the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616:

make CHIP=bl616 BOARD=bl616dk
3
Flash the Firmware

Connect the board with a USB cable, hold the BOOT button (IO2 on the Ai-M61-32S-Kit), briefly press EN/RST to enter download mode, then flash (replace the serial port with the one on your computer):

make flash CHIP=bl616 COMX=/dev/ttyUSB0
4
Run and Verify

Open a serial tool (baud rate 2000000). The example runs 5 algorithm checks in sequence: FIR filter (riscv_dsp2_fir_q15), matrix multiply (matrix_q31), real FFT (rfft_q15), sine (sin_q31), variance (variance_q15). Each compares its output against precomputed reference values; when all pass it prints Example all successfully!.

Code Execution Flow

The flow from boot to verification is:

APIs Used by the Example

csi_sin_q31(x)

Computes sine with Q31 fixed-point input/output; the example verifies 128 input points against reference values.

Parameters:

  • x: angle in Q31 format

Returns: sine value in Q31 format

riscv_dsp2_fir_q15 / riscv_dsp2_rfft_q15, etc.()

Entry functions of each case in cases/ (renamed by macros in main.c); they use the FIR/FFT/matrix/variance APIs from csi_math.h and compare against ref_result.

Parameters: none

Returns: 0; on failure it halts in while(1)

csi_math.h(header)

The DSP library's public header, declaring csi_sin_q31, csi_fir_q15, csi_rfft_q15, csi_mat_q31, csi_var_q15, etc. Include "csi_math.h" in your project to use them.

Parameters: —

Returns: —

Complete Code

The following is the complete source of dsp/main.c and one case (riscv_dsp2_sin_q31.c), identical to the official example, collapsed by default (the other 4 cases have the same structure and live in cases/):

📜 Click to expand dsp/main.c full code
c
#include "bflb_mtimer.h"
#include "board.h"

#define DBG_TAG "MAIN"
#include "log.h"

#define main       riscv_dsp2_fir_q15
#define ref_result ref_result_riscv_dsp2_fir_q15
#define result     result_riscv_dsp2_fir_q15
#define src        src_riscv_dsp2_fir_q15
#include "cases/riscv_dsp2_fir_q15.c"
#undef main
#undef ref_result
#undef result
#undef src
#undef TEST_SIZE

#define main       riscv_dsp2_matrix_q31
#define ref_result ref_result_riscv_dsp2_matrix_q31
#define result     result_riscv_dsp2_matrix_q31
#define src        src_riscv_dsp2_matrix_q31
#include "cases/riscv_dsp2_matrix_q31.c"
#undef main
#undef ref_result
#undef result
#undef src
#undef TEST_SIZE

#define main       riscv_dsp2_rfft_q15
#define ref_result ref_result_riscv_dsp2_rfft_q15
#define result     result_riscv_dsp2_rfft_q15
#define src        src_riscv_dsp2_rfft_q15
#include "cases/riscv_dsp2_rfft_q15.c"
#undef main
#undef ref_result
#undef result
#undef src
#undef TEST_SIZE

#define main       riscv_dsp2_sin_q31
#define ref_result ref_result_riscv_dsp2_sin_q31
#define result     result_riscv_dsp2_sin_q31
#define src        src_riscv_dsp2_sin_q31
#include "cases/riscv_dsp2_sin_q31.c"
#undef main
#undef ref_result
#undef result
#undef src
#undef TEST_SIZE

#define main       riscv_dsp2_variance_q15
#define ref_result ref_result_riscv_dsp2_variance_q15
#define result     result_riscv_dsp2_variance_q15
#define src        src_riscv_dsp2_variance_q15
#include "cases/riscv_dsp2_variance_q15.c"
#undef main
#undef ref_result
#undef result
#undef src
#undef TEST_SIZE

int main(void)
{
    board_init();

    printf("Example run riscv_dsp2_fir_q15!\r\n");
    riscv_dsp2_fir_q15();
    printf("Example run riscv_dsp2_matrix_q31!\r\n");
    riscv_dsp2_matrix_q31();
    printf("Example run riscv_dsp2_rfft_q15!\r\n");
    riscv_dsp2_rfft_q15();
    printf("Example run riscv_dsp2_fir_q15!\r\n");
    riscv_dsp2_sin_q31();
    printf("Example run riscv_dsp2_variance_q15!\r\n");
    riscv_dsp2_variance_q15();
    printf("Example all successfully!\r\n");

    while (1) {
        bflb_mtimer_delay_ms(1000);
    }
}
📜 Click to expand cases/riscv_dsp2_sin_q31.c full code
c
#include <stdio.h>
#include <math.h>
#include "csi_math.h"

#define TEST_SIZE 128

static q31_t src[TEST_SIZE] = {
    0x71f40eb8, 0x1aedfac4, 0x0f3ff639, 0x40eb378a, 0x159f1974, 0x5428ca42, 0x3e990f9d, 0x209a58e6,
    0x62875be9, 0x5816212a, 0x28a6ff13, 0x7a51f6a7, 0x3ca51dcd, 0x052989e9, 0x613a6877, 0x413bbd0c,
    0x502a2298, 0x44af92d2, 0x1851b3ba, 0x531d1932, 0x5259e962, 0x36537413, 0x457bf10d, 0x6f43906c,
    0x473fcc60, 0x3ed09220, 0x2a151a9b, 0x12b52c1b, 0x3f79f6a8, 0x0aea56a5, 0x7f5ab471, 0x0ee05125,
    0x2ec0f1de, 0x2b59847b, 0x6da9fe05, 0x0aa207c9, 0x4e0db117, 0x1ad037ab, 0x78555489, 0x2005ef5a,
    0x107b129e, 0x36df9796, 0x4687e80b, 0x732d0ac1, 0x534c3c63, 0x1c0f8e39, 0x30b19f31, 0x19f18910,
    0x3850eca4, 0x10118818, 0x45a0df62, 0x4104e5c3, 0x14195691, 0x74162b17, 0x5b9f737e, 0x445d0125,
    0x1df54a61, 0x788e5af7, 0x3bc0bd34, 0x0f07e8f3, 0x211f4d64, 0x31a834bb, 0x506dd274, 0x6bb74d4b,
    0x66e132bc, 0x263e92dd, 0x5cb47ec9, 0x541f4af5, 0x2320126d, 0x58b7700e, 0x00d0828f, 0x1182b519,
    0x3d33cf33, 0x6577c618, 0x22af9e0f, 0x058ffea4, 0x2bf32d25, 0x07fb97e5, 0x7895e5f5, 0x73b5f4dd,
    0x0399834c, 0x52f68eac, 0x66311a01, 0x3690ee7d, 0x1258b0e3, 0x1d85a331, 0x28e0511a, 0x1485ae28,
    0x556e56c5, 0x690aa18a, 0x040672e5, 0x5c14209e, 0x5d8ff577, 0x61ba1095, 0x27c2e01e, 0x797a7a8f,
    0x2d957473, 0x2a0c920a, 0x5b8d5230, 0x4c5e6a70, 0x62c33c82, 0x552b8cf0, 0x52a5adae, 0x3023134c,
    0x2015d046, 0x734945c9, 0x73233bd0, 0x4e0a9921, 0x52fc390d, 0x02b26459, 0x25ea9d61, 0x4197a318,
    0x55b9ca53, 0x6eb23e44, 0x31862277, 0x7b8f7be8, 0x2c0cc008, 0x533a8b83, 0x6a35c724, 0x0a232bc0,
    0x2e6247d9, 0x3b442980, 0x1de30e64, 0x749b41b2, 0x70834a66, 0x01f8428b, 0x56356d0a, 0x4708a91b
};

static q31_t ref_result[TEST_SIZE] = {
    0xae927d72, 0x7c0dcc9a, 0x571dc1b4, 0xfa3a9ce8, 0x6fbe4766, 0x950553ac, 0x08cd75d4, 0x7ff10d88,
    0x80fc5f3e, 0x8989e528, 0x74a02914, 0xdcc60f08, 0x14fc107a, 0x2016c0b4, 0x803bb9f2, 0xf841608c,
    0xa4c37a12, 0xe2d13fdc, 0x7701f3ce, 0x98c47cba, 0x9babda5e, 0x3a861816, 0xddf4f932, 0xa247ba02,
    0xd36834fe, 0x0771665a, 0x70a392a6, 0x65b47542, 0x034a13ca, 0x4158f3d2, 0xfbf19cc6, 0x55615368,
    0x5fdfbdea, 0x6ca44370, 0x9bbb0ff4, 0x3fd0ad96, 0xae8a0976, 0x7bdf3ff8, 0xd0f56b9a, 0x7fffc56a,
    0x5c9ea4d4, 0x3771a934, 0xd7aa340e, 0xb4a477aa, 0x9816491c, 0x7d9cd9ea, 0x575fbe36, 0x7a621b14,
    0x2f245878, 0x5acfe2d2, 0xdd15a2fa, 0xf9996cf4, 0x6ac53b20, 0xb9575c24, 0x82f21454, 0xe4cb524a,
    0x7f5b34f4, 0xd2434f50, 0x1a7e13a4, 0x561a435e, 0x7fcdac80, 0x52dadf6a, 0xa39b2218, 0x94978822,
    0x873b677e, 0x7a08961a, 0x81ac072c, 0x95262c98, 0x7e7e8b94, 0x8818541c, 0x051dbcf2, 0x60f7405a,
    0x1185c64c, 0x849581a0, 0x7ee31fd6, 0x2284557a, 0x6a99f2be, 0x30e22044, 0xd26fa1a0, 0xb76248d4,
    0x167fd962, 0x9954214a, 0x85de5864, 0x392d8c3e, 0x644f642a, 0x7f0db084, 0x7409edc4, 0x6c371202,
    0x90d846b8, 0x8c670202, 0x19206920, 0x825db7b6, 0x80eac460, 0x8075db58, 0x76d279d2, 0xd7b86778,
    0x6494f30e, 0x70bd232c, 0x830a5b0a, 0xb6f92e88, 0x812cf66e, 0x91aab728, 0x9a86f676, 0x59e5afda,
    0x7fff28b2, 0xb53400a0, 0xb472be58, 0xae98fc86, 0x993ebfe8, 0x10e525f8, 0x7aa33c5c, 0xf60164b2,
    0x8feff520, 0x9fe370c6, 0x537dd3cc, 0xe4538b3e, 0x6a40ae5e, 0x98572fc8, 0x8fbe4fce, 0x3d18f9cc,
    0x61655134, 0x1d79d4fc, 0x7f4f471a, 0xbc1671de, 0xa7cc325e, 0x0c5b6644, 0x8e80c89c, 0xd4adac08
};

int main(void)
{
    q31_t result;
    int i;

    for (i = 0; i < TEST_SIZE; i++) {
        result = csi_sin_q31(src[i]);

        if (result != ref_result[i]) {
            printf("Example run failed!\r\n");
            while (1)
                ;
        }
    }

    printf("Example run successfully!\r\n");

    return 0;
}

FAQ

\"Example run failed!\" and the program hangs?

A case's output differs from its reference values. Usually the case files were modified or the build optimized unexpectedly; restore the cases/ directory and rebuild — normally all 5 groups pass.

Why Q15/Q31 instead of float?

Fixed point needs no FPU (or avoids slow software floats), is faster, and gives deterministic results — ideal for real-time signal processing. Use Q formats for fractions (q31 is 1.31) and shift after operations to restore scale.

How do I use the DSP library in my own project?

Enable the DSP library in defconfig (e.g., CONFIG_DSP=y per the SDK component docs), then #include "csi_math.h" and call csi_sin_q31, csi_fir_q15, csi_rfft_q15, etc.

Can these cases become real applications?

Yes. Replace src with your sampled data and turn the ref_result comparison into business logic — e.g., feed microphone samples into csi_fir_q15 for denoising, then output to I2S playback.

Released under the MIT License. Build Time 2026-09-11 14:52:23