Johan_Ha
Published

Sound orientating robot

A robot car using two microphones to detect direction of sound.

39
Sound orientating robot

Things used in this project

Hardware components

Infineon cy8cproto-062-4343w
×1

Software apps and online services

ModusToolbox™ Software
Infineon ModusToolbox™ Software
Arduino IDE
Arduino IDE
Audacity

Story

Read more

Code

main.c

C/C++
/******************************************************************************
* File Name:   main.c
*
* Description: This is the source code for the PDM PCM Example
*              for ModusToolbox.
*
* Related Document: See README.md 
*
*
*******************************************************************************
* Copyright 2021-2022, Cypress Semiconductor Corporation (an Infineon company) or
* an affiliate of Cypress Semiconductor Corporation.  All rights reserved.
*
* This software, including source code, documentation and related
* materials ("Software") is owned by Cypress Semiconductor Corporation
* or one of its affiliates ("Cypress") and is protected by and subject to
* worldwide patent protection (United States and foreign),
* United States copyright laws and international treaty provisions.
* Therefore, you may use this Software only as provided in the license
* agreement accompanying the software package from which you
* obtained this Software ("EULA").
* If no EULA applies, Cypress hereby grants you a personal, non-exclusive,
* non-transferable license to copy, modify, and compile the Software
* source code solely for use in connection with Cypress's
* integrated circuit products.  Any reproduction, modification, translation,
* compilation, or representation of this Software except as specified
* above is prohibited without the express written permission of Cypress.
*
* Disclaimer: THIS SOFTWARE IS PROVIDED AS-IS, WITH NO WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT, IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Cypress
* reserves the right to make changes to the Software without notice. Cypress
* does not assume any liability arising out of the application or use of the
* Software or any product or circuit described in the Software. Cypress does
* not authorize its products for use in any products where a malfunction or
* failure of the Cypress product may reasonably be expected to result in
* significant property damage, injury or death ("High Risk Product"). By
* including Cypress's product in a High Risk Product, the manufacturer
* of such system or application assumes all risk of such use and in doing
* so agrees to indemnify Cypress against all liability.
*
*
*  ADDITION by Johan Halmén
*
*  This main.c file was edited to accomplish a task where the built in microphone
*  of the CY8CPROTO board is to detect the direction of the sound.
*
*******************************************************************************/

#include "cyhal.h"
#include "cybsp.h"
#include "cy_retarget_io.h"

#include "stdlib.h"

/*******************************************************************************
* Macros
********************************************************************************/
/* Define how many samples in a frame */
#define FRAME_SIZE                  (128) // 1024
/* Noise threshold hysteresis */
#define THRESHOLD_HYSTERESIS        3u
/* Volume ratio for noise and print purposes */
#define VOLUME_RATIO                (4*FRAME_SIZE)
/* Desired sample rate. Typical values: 8/16/22.05/32/44.1/48kHz */
#define SAMPLE_RATE_HZ              16000u
/* Decimation Rate of the PDM/PCM block. Typical value is 64 */
#define DECIMATION_RATE             64u
/* Audio Subsystem Clock. Typical values depends on the desire sample rate:
- 8/16/48kHz    : 24.576 MHz
- 22.05/44.1kHz : 22.579 MHz */
#define AUDIO_SYS_CLOCK_HZ          24576000u
/* PDM/PCM Pins */
#define PDM_DATA                    P10_5
#define PDM_CLK                     P10_4

/*******************************************************************************
* Function Prototypes
********************************************************************************/
void button_isr_handler(void *arg, cyhal_gpio_event_t event);
void pdm_pcm_isr_handler(void *arg, cyhal_pdm_pcm_event_t event);
void clock_init(void);

int32_t cubic_interpolation(int16_t y0, int16_t y1, int16_t y2, int16_t y3, float mu);
float splinterpol(int16_t y0, int16_t y1, float sly0, float sly1, float t);

int direction(int *significance);

/*******************************************************************************
* Global Variables
********************************************************************************/
/* Interrupt flags */
volatile bool button_flag = false;
volatile bool pdm_pcm_flag = true;

/* Volume variables */
uint32_t volumeL = 0, volumeR = 0;
uint32_t noise_threshold = THRESHOLD_HYSTERESIS;

/* HAL Object */
cyhal_pdm_pcm_t pdm_pcm;
cyhal_clock_t   audio_clock;
cyhal_clock_t   pll_clock;

int16_t  audio_frame[FRAME_SIZE] = {0};
float  interpolatedL[((FRAME_SIZE / 2) - 1) * 4 + 1];
float  interpolatedR[((FRAME_SIZE / 2) - 1) * 4 + 1];
float slope[FRAME_SIZE / 2];

/* HAL Config */
const cyhal_pdm_pcm_cfg_t pdm_pcm_cfg = 
{
    .sample_rate     = SAMPLE_RATE_HZ,
    .decimation_rate = DECIMATION_RATE,
    .mode            = CYHAL_PDM_PCM_MODE_STEREO, 
    .word_length     = 16,  /* bits */
    .left_gain       = 0,   /* dB */
    .right_gain      = 0,   /* dB */
};

/*This structure is used to initialize callback*/
cyhal_gpio_callback_data_t cb_data =
    {
        .callback = button_isr_handler,
        .callback_arg = NULL
 };


/*******************************************************************************
* Function Name: main
********************************************************************************
* Summary:
* The main function for Cortex-M4 CPU does the following:
*  Initialization:
*  - Initializes all the hardware blocks
*  Do forever loop:
*  - Check if PDM/PCM flag is set. If yes, report the current volume
*  - Update the LED status based on the volume and the noise threshold
*  - Check if the User Button was pressed. If yes, reset the noise threshold
*
* Parameters:
*  void
*
* Return:
*  int
*
*******************************************************************************/
int main(void)
{
    cy_rslt_t result;


    /* Initialize the device and board peripherals */
    result = cybsp_init() ;
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }

    /* Enable global interrupts */
    __enable_irq();

    /* Init the clocks */
    clock_init();

    /* Initialize retarget-io to use the debug UART port */
    cy_retarget_io_init(CYBSP_DEBUG_UART_TX, CYBSP_DEBUG_UART_RX, CY_RETARGET_IO_BAUDRATE);

    /* Initialize the User LED */
    cyhal_gpio_init(CYBSP_USER_LED, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG, CYBSP_LED_STATE_OFF);

    /* Initialize the User Button */
    cyhal_gpio_init(CYBSP_USER_BTN, CYHAL_GPIO_DIR_INPUT, CYHAL_GPIO_DRIVE_PULLUP, CYBSP_BTN_OFF);
    cyhal_gpio_enable_event(CYBSP_USER_BTN, CYHAL_GPIO_IRQ_FALL, CYHAL_ISR_PRIORITY_DEFAULT, true);
    cyhal_gpio_register_callback(CYBSP_USER_BTN, &cb_data);

    /* Initialize the PDM/PCM block */
    cyhal_pdm_pcm_init(&pdm_pcm, PDM_DATA, PDM_CLK, &audio_clock, &pdm_pcm_cfg);
    cyhal_pdm_pcm_register_callback(&pdm_pcm, pdm_pcm_isr_handler, NULL);
    cyhal_pdm_pcm_enable_event(&pdm_pcm, CYHAL_PDM_PCM_ASYNC_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true);
    cyhal_pdm_pcm_start(&pdm_pcm);
    
    /* \x1b[2J\x1b[;H - ANSI ESC sequence for clear screen */
    //printf("\x1b[2J\x1b[;H");

    printf("johan\r\n");

#define THRESHOLD 13000

    while(true)
    {
    	int relia;
    	int direc;

    	direc = direction(&relia);
    	if (relia)
    	{
    		printf("\r\n", direc);
            cyhal_pdm_pcm_read_async(&pdm_pcm, audio_frame, FRAME_SIZE);
        }


        cyhal_syspm_sleep();

    }
}

/*******************************************************************************
* Function Name: button_isr_handler
********************************************************************************
* Summary:
*  Button ISR handler. Set a flag to be processed in the main loop.
*
* Parameters:
*  arg: not used
*  event: event that occurred
*
*******************************************************************************/
void button_isr_handler(void *arg, cyhal_gpio_event_t event)
{
    (void) arg;
    (void) event;

    button_flag = true;
}

/*******************************************************************************
* Function Name: pdm_pcm_isr_handler
********************************************************************************
* Summary:
*  PDM/PCM ISR handler. Set a flag to be processed in the main loop.
*
* Parameters:
*  arg: not used
*  event: event that occurred
*
*******************************************************************************/
void pdm_pcm_isr_handler(void *arg, cyhal_pdm_pcm_event_t event)
{
    (void) arg;
    (void) event;

    pdm_pcm_flag = true;
}

/*******************************************************************************
* Function Name: clock_init
********************************************************************************
* Summary:
*  Initialize the clocks in the system.
*
*******************************************************************************/
void clock_init(void)
{
    /* Initialize the PLL */
    cyhal_clock_reserve(&pll_clock, &CYHAL_CLOCK_PLL[0]);
    cyhal_clock_set_frequency(&pll_clock, AUDIO_SYS_CLOCK_HZ, NULL);
    cyhal_clock_set_enabled(&pll_clock, true, true);

    /* Initialize the audio subsystem clock (CLK_HF[1]) 
     * The CLK_HF[1] is the root clock for the I2S and PDM/PCM blocks */
    cyhal_clock_reserve(&audio_clock, &CYHAL_CLOCK_HF[1]);

    /* Source the audio subsystem clock from PLL */
    cyhal_clock_set_source(&audio_clock, &pll_clock);
    cyhal_clock_set_enabled(&audio_clock, true, true);
}

/* [] END OF FILE */

int32_t cubic_interpolation(int16_t y0, int16_t y1, int16_t y2, int16_t y3, float mu) {
	int16_t a0, a1, a2, a3;
    float mu2;

    mu2 = mu * mu;
    a0 = y3 - y2 - y0 + y1;
    a1 = y0 - y1 - a0;
    a2 = y2 - y0;
    a3 = y1;

    return (int32_t)(mu * a0 * mu2 + mu2 * a1 + mu * a2 + a3);
}

float* expand_array(float* arr, int n) {
    int i;
    float* expanded_arr = (float*) malloc((n * 4 - 3) * sizeof(float));

    for (i = 0; i < n - 1; i++) {
        expanded_arr[i * 4] = arr[i];
        expanded_arr[i * 4 + 1] = cubic_interpolation(arr[i], arr[i + 1], arr[i + 2], arr[i + 3], 0.0);
        expanded_arr[i * 4 + 2] = cubic_interpolation(arr[i], arr[i + 1], arr[i + 2], arr[i + 3], 0.5);
        expanded_arr[i * 4 + 3] = cubic_interpolation(arr[i], arr[i + 1], arr[i + 2], arr[i + 3], 1.0);
    }

    expanded_arr[n * 4 - 4] = arr[n - 1];

    return expanded_arr;
}

float splinterpol(int16_t y0, int16_t y3, float sly0, float sly1, float t)
{
	float u = 1.0 - t;
	float y1, y2;
	y1 = y0 + sly0 / 3.;
	y2 = y3 - sly1 / 3.;

	return y0 * u * u * u + y1 * u * u * t * 3 + y2 * u * t * t * 3 + y3 * t * t * t;
}

int direction(int *significance)
{

    if (!pdm_pcm_flag)
    {
    	// No sound ready
    	*significance = 0;
    	return 0;
    }

    // Ok, we have a recorded sound
    {
        /* Clear the PDM/PCM flag */
        pdm_pcm_flag = 0;

        float smallest, summer;
        int smallest_i;

        // Create interpolated arrays
        //    Slope for Left. Each sample point gets a calculated slope.

        for (int i = 2; i < FRAME_SIZE-2; i += 2)
        {
        	slope[i / 2] = (float)(audio_frame[i + 2] - audio_frame[i - 2]) / 2;
        }
        slope[0] = (audio_frame[2] - slope[1] / 3 - audio_frame[0]) * 3 / 2;
        slope[FRAME_SIZE / 2 - 1] = (audio_frame[FRAME_SIZE - 4] + slope[FRAME_SIZE / 2 - 2] / 3 - audio_frame[FRAME_SIZE - 2]) * 3 / 2;

        for (int i = 0; i < FRAME_SIZE / 2 - 1; i++)
        {
        	interpolatedL[i * 4] = audio_frame[i * 2];
        	interpolatedL[i * 4 + 1] = splinterpol(audio_frame[2*i], audio_frame[2*i+2], slope[i], slope[i+1], 0.25);
        	interpolatedL[i * 4 + 2] = splinterpol(audio_frame[2*i], audio_frame[2*i+2], slope[i], slope[i+1], 0.5);
        	interpolatedL[i * 4 + 3] = splinterpol(audio_frame[2*i], audio_frame[2*i+2], slope[i], slope[i+1], 0.75);

        }
        interpolatedL[((FRAME_SIZE / 2) - 1) * 4] = audio_frame[FRAME_SIZE-2];

        // Create interpolated arrays
        //    Slope for Right

        for (int i = 2; i < FRAME_SIZE-2; i += 2)
        {
        	slope[i / 2] = (float)(audio_frame[i + 3] - audio_frame[i - 1]) / 2;

        }
        slope[0] = (audio_frame[3] - slope[1] / 3 - audio_frame[1]) * 3 / 2;
        slope[FRAME_SIZE / 2 - 1] = (audio_frame[FRAME_SIZE - 3] + slope[FRAME_SIZE / 2 - 2] / 3 - audio_frame[FRAME_SIZE - 1]) * 3 / 2;

        for (int i = 0; i < FRAME_SIZE / 2 - 1; i++)
        {
        	interpolatedR[i * 4] = audio_frame[i * 2 + 1];
        	interpolatedR[i * 4 + 1] = splinterpol(audio_frame[2*i+1], audio_frame[2*i+3], slope[i], slope[i+1], 0.25);
        	interpolatedR[i * 4 + 2] = splinterpol(audio_frame[2*i+1], audio_frame[2*i+3], slope[i], slope[i+1], 0.5);
        	interpolatedR[i * 4 + 3] = splinterpol(audio_frame[2*i+1], audio_frame[2*i+3], slope[i], slope[i+1], 0.75);

        }
        interpolatedR[((FRAME_SIZE / 2) - 1) * 4] = audio_frame[FRAME_SIZE-1];

        // Ok, now we have a left and a right wave, four times larger than the original recording
        // Find now how much they are time shifted.

        smallest = 1E38; // Start with an insanely large comparison number
        for (int i = -8; i <= 8; i++) // and go through all 17 possible cases
        {
        	summer = 0;
        	for (int j = 8; j < FRAME_SIZE * 2 - 8; j ++)
        	{
        		summer += (interpolatedL[j] - interpolatedR[j + i]) * (interpolatedL[j] - interpolatedR[j + i]);

        	}
        	if (summer < smallest)
        	{
        		smallest = summer;
        		smallest_i = i;
        	}
        }

        return smallest_i;

    }

}

Credits

Johan_Ha

Johan_Ha

15 projects • 24 followers
Music teacher Composer Coding for fun

Comments