CMSIS DSP library support (arm_math.h)

I’ve been trying to get FFTS working as well. Using the additions to the makefile that @fredyeah suggested, it’s linking the .c files. However, it seems one of the files required for arm_rfft_fast_f32 is arm_bitreversal2.S.

Since this is an assembly file, the makefile doesn’t seem to have a rule for passing it to the compiler. I’ve tried several things, but I can’t seem to get it to work. Does anyone know how to set up the makefile to get this to work? This is the first time I’ve ever used makefiles and I’m finding it a bit confusing.

Or if anyone knows of any open source projects using FFTs on the Daisy, that would help immensely. I’ve not been able to find any code using FFTs to use as a model.

Thanks for the help.

Google ‘make implicit rules’.

Makefiles can be confusing, they are super important.

Bump~~ this is the exact issue I am having

I haven’t done it with wildcarding, but there are three variables that need to be edited/set to work add the CMSIS files.
I was only using a few things when I was experimenting so the C_SOURCES list is fairly short.
However, as many files as needed can be added manually. It should also be able to be set with a wildcard similar to above.

This can sneak by until you hit the compiler error:

ASM_SOURCES = \
$(LIBDAISY_DIR)/Drivers/CMSIS/DSP/Source/TransformFunctions/arm_bitreversal2.s

here are a few of the c sources

C_SOURCES = \
$(LIBDAISY_DIR)/Drivers/CMSIS/DSP/Source/TransformFunctions/arm_rfft_fast_f32.c \
$(LIBDAISY_DIR)/Drivers/CMSIS/DSP/Source/TransformFunctions/arm_rfft_fast_init_f32.c \
$(LIBDAISY_DIR)/Drivers/CMSIS/DSP/Source/CommonTables/arm_common_tables.c \
$(LIBDAISY_DIR)/Drivers/CMSIS/DSP/Source/CommonTables/arm_const_structs.c \
$(LIBDAISY_DIR)/Drivers/CMSIS/DSP/Source/TransformFunctions/arm_cfft_f32.c \
$(LIBDAISY_DIR)/Drivers/CMSIS/DSP/Source/TransformFunctions/arm_bitreversal.c \
$(LIBDAISY_DIR)/Drivers/CMSIS/DSP/Source/TransformFunctions/arm_cfft_radix8_f32.c

and lastly the Include folder has to be added for all of the header files

C_INCLUDES += \
-I$(LIBDAISY_DIR)/Drivers/CMSIS/DSP/Include 

These can be done in any order as long as they’re above the final include statement.

Hope that helps!

1 Like

$(LIBDAISY_DIR)/Drivers/CMSIS/DSP/Source/TransformFunctions/arm_bitreversal2.s doesn’t exist - it’s the product of running CPP on arm_bitreversal2.S

At least, that’s how it looks on my Mac.

how do I add a rule for this file ?

make: *** No rule to make target ‘build/arm_bitreversal2.o’, needed by ‘build/MyProject.elf’. Stop.

can you be more specific ? cpp is not an executable, do you mean gcc ? also the source is assembly (.S not .cpp)

arm-none-eabi-cpp is the ‘C preprocessor’ - it handles expansion of macros like #if, #ifdef, #include, etc. It’s not just for C, also useful for c++, assembler and anything else that needs this type of macro expansion.

The point is that .S files might have macros that need preprocessing, and .s files don’t. doesn’t include a rule for transforming a .S file to a .o file.

There are various ways to get this to build, but I haven’t figured out a good one which doesn’t involve hacking DaisyExamples/libDaisy/core/Makefile .

lol
ok I renamed that stupid file and voilà

2 Likes

Exactly, you got it, congrats.

1 Like

section .data' will not fit in region FLASH’

how can I prune my code, which is just doing an FFT->iFFT and nothing else ?

#include "daisy_seed.h"
#include "daisysp.h"
#include "arm_math.h"

// Use the daisy namespace to prevent having to type
// daisy:: before all libdaisy functions
using namespace daisy;
using namespace daisysp;

// Declare a DaisySeed object called hardware
DaisySeed  hardware;
Oscillator osc;
AdEnv      env;

arm_rfft_fast_instance_f32* fftInstance;
float32_t *fftBuffer;

void AudioCallback(AudioHandle::InterleavingInputBuffer  in,
                   AudioHandle::InterleavingOutputBuffer out,
                   size_t                                size)
{
    float osc_out;

    //Fill the block with samples
    for(size_t i = 0; i < size; i += 2)
    {
        osc_out = osc.Process();

        //Set the left and right outputs
        out[i]     = osc_out;
        // out[i + 1] = osc_out;
        out[i+1] = in[i+1];
                
        arm_rfft_fast_f32(fftInstance,(float32_t*)&in[0],fftBuffer,0);

        arm_rfft_fast_f32(fftInstance,fftBuffer,(float32_t*)&out[0],1);
    }
}

int main(void)
{
    // Declare a variable to store the state we want to set for the LED.
    bool led_state;
    led_state = true;

    // Configure and Initialize the Daisy Seed
    // These are separate to allow reconfiguration of any of the internal
    // components before initialization.
    hardware.Configure();
    hardware.Init();
    hardware.SetAudioBlockSize(4);

    //How many samples we'll output per second
    float samplerate = hardware.AudioSampleRate();

    fftInstance = new arm_rfft_fast_instance_f32;
    arm_status status = arm_rfft_fast_init_f32(fftInstance, hardware.AudioBlockSize());
    fftBuffer = new float32_t[hardware.AudioBlockSize()];

    //Set up oscillator
    osc.Init(samplerate);
    osc.SetWaveform(osc.WAVE_SIN);
    osc.SetAmp(1.f);
    osc.SetFreq(440);

    hardware.StartAudio(AudioCallback);

    // Loop forever
    for(;;)
    {
        // Set the onboard LED
        hardware.SetLed(led_state);

        // Toggle the LED state for the next time around.
        led_state = !led_state;

        // Wait 500ms
        System::Delay(500);
    }
}

Hey Phil!

Thank you for the wait.

The cause of that error is the result of objects being too big to fit in the data section. You can try moving some of the stuff to SDRAM.
Our guess is that the fftInstance is the really big thing that should be moved.
So, arm_rfft_fast_instance_f32 DSY_SDRAM_BSS fftInstance; to move that object to the SDRAM.

Also, new is not typically used in embedded in our experience and will require some refactoring to use the SDRAM. Therefore, everywhere you reference it needs to be changed to &fftInstance.

We hope this helps!!

Thanks, it helped indeed

1 Like

… and for future newbs like me ( in fact, probably precisely me next time I hit this error ) the file to rename is

cd ./libDaisy/Drivers/CMSIS/DSP/Source/TransformFunctions/
mv arm_bitreversal2.S arm_bitreversal2.s
2 Likes

I’m still struggling to fit this on my patch.init(), anyone had sucess here? In this minimal example (that doesn’t make sense, just trying to compile), both fft instance and buffer are on SDRAM_BSS but still no joy - any ideas?

/Applications/ArmGNUToolchain/12.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/12.3.1/../../../../arm-none-eabi/bin/ld: build/spectral.elf section `.text' will not fit in region `FLASH'
/Applications/ArmGNUToolchain/12.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/12.3.1/../../../../arm-none-eabi/bin/ld: region `FLASH' overflowed by 68868 bytes
/Applications/ArmGNUToolchain/12.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/12.3.1/../../../../arm-none-eabi/bin/ld: warning: build/spectral.elf has a LOAD segment with RWX permissions
Memory region         Used Size  Region Size  %age Used
           FLASH:      199940 B       128 KB    152.54%
         DTCMRAM:          0 GB       128 KB      0.00%
            SRAM:       13864 B       512 KB      2.64%
          RAM_D2:       16896 B       288 KB      5.73%

The main source of program memory usage with CMSIS DSP FFT stuff is the constant lookup table (LUT) data used for various sizes of FFT. I believe in older versions of CMSIS DSP all the LUTs for all the supported sizes are linked into program data, whereas with the newer versions allow you to specify which ones you want to compile/include via preprocessor definitions.

The latest main branch of libDaisy was recently updated with a newer CMSIS DSP version and if you’re up-to-date with the main branch, something like this will work in your makefile (adapted from one of my own projects).

# Config Options
MY_FFT_SIZE = 1024

# Definitions for FFT
C_DEFS += -DARM_DSP_CONFIG_TABLES -DARM_FFT_ALLOW_TABLES

ifeq ($(MY_FFT_SIZE), 512)
C_DEFS += -DARM_TABLE_TWIDDLECOEF_F32_256 -DARM_TABLE_BITREVIDX_FLT_256 -DARM_TABLE_TWIDDLECOEF_RFFT_F32_512
endif
ifeq ($(MY_FFT_SIZE), 1024)
C_DEFS += -DARM_TABLE_TWIDDLECOEF_F32_512 -DARM_TABLE_BITREVIDX_FLT_512 -DARM_TABLE_TWIDDLECOEF_RFFT_F32_1024
endif
ifeq ($(MY_FFT_SIZE), 2048)
C_DEFS += -DARM_TABLE_TWIDDLECOEF_F32_1024 -DARM_TABLE_BITREVIDX_FLT_1024 -DARM_TABLE_TWIDDLECOEF_RFFT_F32_2048
endif
ifeq ($(MY_FFT_SIZE), 4096)
C_DEFS += -DARM_TABLE_TWIDDLECOEF_F32_2048 -DARM_TABLE_BITREVIDX_FLT_2048 -DARM_TABLE_TWIDDLECOEF_RFFT_F32_4096
endif

# ... rest of makefile ...

It’s a little bit clumsy to do it like this, but it works - whatever MY_FFT_SIZE is set to determines which LUTs are actually compiled and linked. There’s also some kind of python configuration tool included with CMSIS-DSP that seems to automate some of this but I’ve not tried to integrate it with the libDaisy Makefile build process.

Of course, with larger FFT sizes the LUT data still might not fit into program memory internal to the STM32, so you may need to use the Daisy Bootloader instead.

3 Likes

Hey as a offshoot to CMSIS ! have you tested using

arm_rfft_fast_f32(&fftInstance,FFTInTemp,FFTOut,0) ;

I’ve got a really slick spectrum display running @60fps 4096 size - it’s fantastic on a 320x170x16bit 2" display. But I noticed that arm_rfft_fast_f32 trashes the input array! Can’t see anything in the docs about that.

Wondering if anyone else has this issue?

thx

This is documented behavior: Real FFT Functions

[in] p points to input buffer (Source buffer is modified by this function.)

If you need to use the input buffer for something else after running the fft, make a copy of it first.

thx - the docs I read didn’t mention the src getting mangled :slight_smile: (or maybe I misinterpreted it in a coding frenzy!)
Guess it’s some radix/butterfly shenanigans doing that under the hood!
I apply a window every frame and my input data is a fifo pipe - hence “FFTInTemp”. I recreate the input every time. Works great and snappy - 4096 size = 1-2ms (shows 1ms at gettick granularity).

1 Like

this is exactly what i’ve been looking for lately! I started my fft project attempting to use cmsis but then diverted to shy_fft after struggling with the LUT issue

1 Like