CMSIS DSP library support (arm_math.h)

I’d like to make an attempt at implementing a FFT pitch shift effect (as opposed to the SOLA implementation used in the current DaisySP library).

I came across this FFT pitch shifter implementation from Zynaptiq that I think could work on Daisy if I could use more the more efficient FFT functions available via arm_math.h (i.e. arm_cfft_radix4_f32()) to adapt it.

Is there any ETA on when the CMSIS libarary will be implemented for Daisy? It seems like the idea has been reviewed to some extent - as the current iteration of the pitchshifter in DaisySP includes arm_math.h, but doesn’t seem to compile if I force it to use arm_sin_f32() - I just get the “arm_math.h” is “undefined” error.

It also looks like libdaisy includes CMSIS and arm_math.h in the driver path:
…DaisyExamples\libDaisy\Drivers\CMSIS\DSP\Include\

It’s just not part of the current build. Is this something that’s on the roadmap for Daisy in the near future?

But it’s source is already included in libDaisy. They probably haven’t added those files to C_SRC variable, so it doesn’t get built. But you should be able to solve this in your project.

Also, CMSIS based FFT was usable on STM32F4 for running FFT and RFFT on a stereo channel. I’d expect it to manage even 4 channels in Daisy.

Thanks for the reply, antisvin!

I initially thought it would be just as easy as including:
/Drivers/CMSIS/DSP/Include

into the Make files for libDaisy and libDaisy core with the #define variable for cortex-m7 MCU (“ARM_MATH_CM7”) - but after a lot of tinkering - it seems that there is something I’m missing.

I can rebuild the libraries without errors and I even get it to stop throwing the “arm_math.h” is “undefined” error…but in it’s place I get “undefined reference to ‘arm_sin_f32’” (or whichever arm_math.h function I use).

Has anyone successfully rebuilt the libraries including the CMSIS DSP headers and gotten something to successfully compile using one of the arm_math.h functions? If so, can you point me to where I may have gone wrong?

It seems that I’ve found a work-around in the meantime.

I stumbled on this stack overflow question and while the poster’s specific issue is about a
stm32f4 device, his issue is the same.

The proposed workaround is to grab the applicable *.c source files from:
…/DaisyExamples/libDaisy/Drivers/CMSIS/DSP/Source/…

and include them in the project directory and the Make file like:
# Sources
CPP_SOURCES = ex_pitchshifter.cpp
C_SOURCES = arm_sin_f32.c arm_common_tables.c

I am able to get the pitchshifter example to compile this way and it runs on the hardware using using the arm_math.h functions exactly as it runs without them.

I imagine there is a better way to define where all of the CMSIS source files are, so I don’t have to include them one-by-one, but the make file already includes:
# Library Locations
LIBDAISY_DIR ?= ../../../libdaisy

[edit]
:arrow_down_small: This is not the answer. :arrow_down_small:

So, I’m guessing that:
CMSIS_DIR ?= ../../../libDaisy/Drivers/CMSIS/DSP/Source/
Isn’t the answer (though, I might give this a go now - just to check).

Long term, would love to just be able to use the functions without the workaround - let me know if anyone has a better solution.

1 Like

Not sure if this is still relevant for anyone, but I think I’ve got it working in my project (trig functions working at least) by adding

C_SOURCES = $(wildcard ../../libDaisy/Drivers/CMSIS/DSP/Source/*/*.c)

to the Makefile. Of course replacing the ../../ with the path to libDaisy.
Then I just #include "arm_math.h" as usual and everything is working for me :slight_smile:

1 Like

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%