Use FFT to handle MEMS microphone data

Hi Nordic,

The proposed approach involves capturing ambient sound from the surroundings to achieve different LED display effects. The current plan is to use an Analog-to-Digital (AD) converter to collect output from MEMS microphones. Subsequently, Fast Fourier Transform (FFT) will be applied to analyze the frequency components of the sound, enabling the implementation of distinct LED display effects based on the frequency variations.

I am not entirely certain whether the ADC of the nRF52832 can achieve this effect. Also, is this approach feasible?

Parents
  • Hi 

    The SAADC module in the nRF52832 does not come with built in FFT capabilities, but the MCU can run FFT algorithms on the ADC data after it has been stored in RAM. 

    The nRF52832 includes the standard ARM Cortex M4 DSP extension, which can be used to accelerate FFT operations. 

    I am not entirely certain whether the ADC of the nRF52832 can achieve this effect. Also, is this approach feasible?

    It's hard to answer this definitely without knowing what kind of effects you are trying to achieve. For instance what kind of FFT resolution would you need, and how often do you need to get a new FFT reading, will affect the CPU performance required. Have you tried to prototype the application on a more high end system, like a PC, to see if the idea is sound? 

    Which SDK are you planning to use for your development? 

    Best regards
    Torbjørn

  • Hi Ovrebekk,

    Thanks for your reply!

    The SAADC module in the nRF52832 does not come with built in FFT capabilities, but the MCU can run FFT algorithms on the ADC data after it has been stored in RAM. 

    This is exactly what I want to do!

    It's hard to answer this definitely without knowing what kind of effects you are trying to achieve. For instance what kind of FFT resolution would you need, and how often do you need to get a new FFT reading, will affect the CPU performance required.

    Due to the relatively low frequency of light visible to the human eye, I intend to use a one-millisecond timer to read ADC data. After obtaining 20 data points (within a period of 20 milliseconds or longer), I plan to use the Fast Fourier Transform (FFT) to determine the corresponding frequencies for each ADC value. Different frequencies within this time frame will correspond to different display effects on LEDs. The specific display effects on the LEDs can be achieved by mapping different frequency magnitudes to varying brightness levels.

    Which SDK are you planning to use for your development? 

    I have been developing using SDK version 17.1.0, so I intend to continue using it.

  • I think the most natural way to implement this is to run the ADC at 10kHz, and simply set an ADC buffer size of 128 samples. Once one buffer is full you hand it over to the FFT processing function, and provide a second 128 sample buffer to the ADC.

    So, you mean that collecting ADC data once every 0.1ms is sufficient to obtain processing results through FFT? I thought it was necessary to collect 128 data points continuously within 0.1ms. In that case, how should I use a 0.1ms timer? The minimum time for timers in the SDK is 1ms.

  • Hi 

    If you sampled 128 data points every 100us you would be massively oversampling the audio signal, this wouldn't give you any meaningful results. 

    Put another way, you can't run FFT on a single audio sample. You need an array of samples to get some frequency content. 

    You can look at the timer example in the SDK for help on setting up a TIMER module. These modules can run up to 16MHz clock frequency, and as such can be used for very accurate timing.

    For 100us timing the code should look something like this:

    const nrf_drv_timer_t TIMER_LED = NRF_DRV_TIMER_INSTANCE(0);
    
    /**
     * @brief Handler for timer events.
     */
    void timer_led_event_handler(nrf_timer_event_t event_type, void* p_context)
    {
        static uint32_t i;
        uint32_t led_to_invert = ((i++) % LEDS_NUMBER);
    
        switch (event_type)
        {
            case NRF_TIMER_EVENT_COMPARE0:
                bsp_board_led_invert(led_to_invert);
                break;
    
            default:
                //Do nothing.
                break;
        }
    }
    
    
    /**
     * @brief Function for main application entry.
     */
    int main(void)
    {
        uint32_t time_us = 100; //Time (in microseconds) between consecutive compare events.
        uint32_t time_ticks;
        uint32_t err_code = NRF_SUCCESS;
    
        //Configure all leds on board.
        bsp_board_init(BSP_INIT_LEDS);
    
        //Configure TIMER_LED for generating simple light effect - leds on board will invert his state one after the other.
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        err_code = nrf_drv_timer_init(&TIMER_LED, &timer_cfg, timer_led_event_handler);
        APP_ERROR_CHECK(err_code);
    
        time_ticks = nrf_drv_timer_us_to_ticks(&TIMER_LED, time_us);
    
        nrf_drv_timer_extended_compare(
             &TIMER_LED, NRF_TIMER_CC_CHANNEL0, time_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);
    
        nrf_drv_timer_enable(&TIMER_LED);
    
        while (1)
        {
            __WFI();
        }
    }

    Best regards
    Torbjørn

  • Thank you for your answer. I will test according to the solution you provided. If I have further questions, I will consult you later.

  • Hi 

    Sounds like a plan Slight smile

    As a side note it is possible to connect the timer directly to the ADC through the PPI peripheral, for more accurate and consistent timing. If you want to explore this route just let me know, and I will see if I can dig up some samples. 

    Best regards
    Torbjørn

  • As a side note it is possible to connect the timer directly to the ADC through the PPI peripheral, for more accurate and consistent timing. If you want to explore this route just let me know, and I will see if I can dig up some samples. 

    That sounds great! I haven't tried the PPI example in the SDK yet, but it seems like a very efficient way to handle things.

Reply Children
No Data
Related