
lab 1 code
Dependencies: CMSIS-DSP_for_STM32F746G BSP_DISCO_F746NG
main.cpp
- Committer:
- justenmg
- Date:
- 2020-01-28
- Revision:
- 34:5bf89ab5e247
- Parent:
- 33:a0dab92ea1b9
File content as of revision 34:5bf89ab5e247:
/** ****************************************************************************** * @file main.c * @author Brian Mazzeo * @date 2020 * @brief This file provides a set of code for signal processing in 487. * Parts are taken from example code from STMIcroelectronics ****************************************************************************** * @attention * This code was specifically developed for BYU ECEn 487 course * Introduction to Digital Signal Processing. * * ****************************************************************************** */ #include "mbed.h" #include "stm32746g_discovery_audio.h" #include "stm32746g_discovery_sdram.h" #include "stm32746g_discovery_lcd.h" #include "signal_processing.h" /* The following type definitions are used to control the * buffering of the audio data using a double buffering technique. * Most of the transactions between the WM8994 and the microcontroller * are handled by other code - but this signals what the buffering state * is, so the data can be appropriately processed. */ typedef enum { BUFFER_OFFSET_NONE = 0, BUFFER_OFFSET_HALF = 1, BUFFER_OFFSET_FULL = 2, } BUFFER_StateTypeDef; /* Scale factor */ #define SCALE_FACTOR ((uint16_t)100) // Scale factor for dividing R L /* These audio block samples define the size of the buffering */ #define AUDIO_SAMPLE_LENGTH ((uint16_t)16) // Bits per sample #define AUDIO_BLOCK_SAMPLES ((uint32_t)128) // Number of samples (L and R) in audio block (each samples is 16 bits) #define AUDIO_BLOCK_SIZE ((uint32_t)512) // Number of bytes in audio block (4 * AUDIO_BLOCK_SAMPLES) /* These RAM addresses are important to determine where the audio data is stored. */ #define SDRAM_DEVICE_ADDR_AUDIO_MEM ((uint32_t)0xC0400000) #define AUDIO_BUFFER_IN SDRAM_DEVICE_ADDR_AUDIO_MEM #define AUDIO_BUFFER_OUT (AUDIO_BUFFER_IN + (AUDIO_BLOCK_SIZE * 2)) /* These definitions define the size of the oscilloscope that is used to display data. */ #define OSC_START_X_POS 20 #define OSC_LINE_SIZE 256 #define OSC_Y_POS 150 #define AUDIO_DRAW_LIMIT 50 /* This define a timer that is then used to record the timing of the different processing stages. */ Timer timer; /* This variable is important because it define the audio buffer recording state. */ volatile uint32_t audio_rec_buffer_state = BUFFER_OFFSET_NONE; /* Function declarations */ static void Erase_Trace(uint16_t Xpos, uint16_t Ypos, uint16_t Length); static void Draw_Trace(uint16_t Xpos, uint16_t Ypos, uint16_t* Mem_start, uint16_t Length); static void Audio_to_Float(uint16_t* buffer_in, float* L_out, float* R_out, uint16_t Length); static void Float_to_Audio(float* L_in, float* R_in, uint16_t* buffer_out, uint16_t Length); /* These memory blocks are important for converting to floating point representation. */ float L_channel_float[AUDIO_BLOCK_SAMPLES]; float R_channel_float[AUDIO_BLOCK_SAMPLES]; float *L_channel_float_p = &L_channel_float[0]; float *R_channel_float_p = &R_channel_float[0]; /* These memory blocks are where the information is stored to send back out to the WM8994 chip. */ uint16_t Processed_audio[AUDIO_BLOCK_SAMPLES]; uint16_t *Processed_audio_p = &Processed_audio[0]; /* Useful variables during looping */ uint32_t counter = 0; // Loop counter char buf[40]; // Character buffer for sprintf statements to the LCD int first_half_time = 0; // Time of first processing block int second_half_time = 0; // Time of second processing block int total_time = 0; // Time of total loop (first and second blocks) /* Main Function */ int main() { /* Initialize the LCD Screen and display information */ BSP_LCD_Init(); BSP_LCD_LayerDefaultInit(LTDC_ACTIVE_LAYER, LCD_FB_START_ADDRESS); BSP_LCD_SelectLayer(LTDC_ACTIVE_LAYER); /* Clear the LCD and set the font to be default */ BSP_LCD_Clear(LCD_COLOR_BLACK); BSP_LCD_SetFont(&LCD_DEFAULT_FONT); /* Set the backcolor to be black and the textcolor to be orange. */ BSP_LCD_SetBackColor(LCD_COLOR_BLACK); BSP_LCD_SetTextColor(LCD_COLOR_ORANGE); /* The following are static display elements that will remain on the screen. */ BSP_LCD_DisplayStringAt(0, 0, (uint8_t *)"487 Lab 1 (student)", LEFT_MODE); /* Display the L and R colors for the channels */ BSP_LCD_SetTextColor(LCD_COLOR_BLUE); BSP_LCD_DisplayStringAt(0, OSC_Y_POS - 20, (uint8_t *)"L", LEFT_MODE); BSP_LCD_SetTextColor(LCD_COLOR_GREEN); BSP_LCD_DisplayStringAt(0, OSC_Y_POS, (uint8_t *)"R", LEFT_MODE); // Draw rectangle and center line for O-scope background BSP_LCD_SetTextColor(LCD_COLOR_YELLOW); BSP_LCD_DrawRect(OSC_START_X_POS - 1, OSC_Y_POS - AUDIO_DRAW_LIMIT - 1, OSC_LINE_SIZE + 2, AUDIO_DRAW_LIMIT*2 + 2); BSP_LCD_SetTextColor(LCD_COLOR_WHITE); BSP_LCD_DrawLine(OSC_START_X_POS, OSC_Y_POS, OSC_START_X_POS + OSC_LINE_SIZE, OSC_Y_POS); /* The following code should not be code that you need to worry about - it sets up the audio interfaces. */ /* Initialize the Audio Interface */ BSP_AUDIO_IN_OUT_Init(INPUT_DEVICE_DIGITAL_MICROPHONE_2, OUTPUT_DEVICE_HEADPHONE, DEFAULT_AUDIO_IN_FREQ, DEFAULT_AUDIO_IN_BIT_RESOLUTION, DEFAULT_AUDIO_IN_CHANNEL_NBR); /* Initialize SDRAM buffers */ BSP_SDRAM_Init(); memset((uint16_t *)AUDIO_BUFFER_IN, 0, AUDIO_BLOCK_SIZE * 2); memset((uint16_t *)AUDIO_BUFFER_OUT, 0, AUDIO_BLOCK_SIZE * 2); /* Start Recording */ if (BSP_AUDIO_IN_Record((uint16_t *)AUDIO_BUFFER_IN, AUDIO_BLOCK_SIZE) != AUDIO_OK) { printf("BSP_AUDIO_IN_Record error\n"); } /* Start Playback */ BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_02); if (BSP_AUDIO_OUT_Play((uint16_t *)AUDIO_BUFFER_OUT, AUDIO_BLOCK_SIZE * 2) != AUDIO_OK) { printf("BSP_AUDIO_OUT_Play error\n"); } /* The audio interfaces are all now working. * Importantly - AUDIO_BUFFER_IN is the pointer to the incoming data from the WM8994 * AUDIO_BUFFER_OUT is the pointer to the outgoing data to the WM8994 */ /* Initialize signal processing filters - usually there are variables that * need to be set up or that there are arrays you need to precompute - this * function call allows you to do that. */ initalize_signal_processing(); /* Hardware timer starts. Set to zero */ timer.start(); /* Main signal processing while loop */ while (1) { /* First Half */ /* Wait until end of half block recording before going on in the first half cycle*/ while (audio_rec_buffer_state != BUFFER_OFFSET_HALF) {} /* This captures the time of an entire cycle */ total_time = timer.read_us(); /* Reset the timer counter to zero */ timer.reset(); /* Plot traces of first half block recording */ Erase_Trace(OSC_START_X_POS, OSC_Y_POS, AUDIO_BLOCK_SAMPLES); Draw_Trace(OSC_START_X_POS, OSC_Y_POS, (uint16_t *) AUDIO_BUFFER_IN, AUDIO_BLOCK_SAMPLES); /* Convert data to floating point representation for processing */ Audio_to_Float((uint16_t *) AUDIO_BUFFER_IN, L_channel_float_p, R_channel_float_p, AUDIO_BLOCK_SAMPLES); /* ------------------------------------------------------------------------ */ /* Here is where signal processing can be done on the floating point arrays */ process_audio_channel_signals(L_channel_float_p, R_channel_float_p, AUDIO_BLOCK_SAMPLES); /* Here is where signal processing can end on the floating point arrays */ /* -------------------------------------------------------------------- */ /* Covert floating point data back to fixed point audio format */ Float_to_Audio(L_channel_float_p, R_channel_float_p, (uint16_t *) Processed_audio, AUDIO_BLOCK_SAMPLES); /* Copy recorded 1st half block into the audio buffer that goes out */ /* Replace the second memcpy with this first one once you have worked out the processed audio functions. */ memcpy((uint16_t *)(AUDIO_BUFFER_OUT), (uint16_t *)(Processed_audio), AUDIO_BLOCK_SIZE); //memcpy((uint16_t *)(AUDIO_BUFFER_OUT), (uint16_t *)(AUDIO_BUFFER_IN), AUDIO_BLOCK_SIZE); /* Display useful cycle information (split up information display so the processing is more balanced) */ sprintf(buf, "Cycles: %9d", counter); BSP_LCD_SetTextColor(LCD_COLOR_RED); BSP_LCD_DisplayStringAt(0, 46, (uint8_t *) buf, LEFT_MODE); /* Capture the timing of the first half processing */ first_half_time = timer.read_us(); /* End First Half */ /* Second Half */ /* Wait end of one block recording */ while (audio_rec_buffer_state != BUFFER_OFFSET_FULL) {} /* Plot traces of second half block recording */ Erase_Trace(OSC_START_X_POS+AUDIO_BLOCK_SAMPLES, OSC_Y_POS, AUDIO_BLOCK_SAMPLES); Draw_Trace( OSC_START_X_POS+AUDIO_BLOCK_SAMPLES, OSC_Y_POS, (uint16_t *) (AUDIO_BUFFER_IN + (AUDIO_BLOCK_SIZE)), AUDIO_BLOCK_SAMPLES); /* Convert data to floating point representation for processing */ Audio_to_Float((uint16_t *) (AUDIO_BUFFER_IN + (AUDIO_BLOCK_SIZE)), L_channel_float_p, R_channel_float_p, AUDIO_BLOCK_SAMPLES); /* ------------------------------------------------------------------------ */ /* Here is where signal processing can be done on the floating point arrays */ process_audio_channel_signals(L_channel_float_p, R_channel_float_p, AUDIO_BLOCK_SAMPLES); /* Here is where signal processing can end on the floating point arrays */ /* -------------------------------------------------------------------- */ /* Covert floating point data back to fixed point audio format */ Float_to_Audio(L_channel_float_p, R_channel_float_p, (uint16_t *) Processed_audio, AUDIO_BLOCK_SAMPLES); /* Copy recorded 2nd half block into the audio buffer that goes out */ memcpy((uint16_t *)(AUDIO_BUFFER_OUT + (AUDIO_BLOCK_SIZE)), (uint16_t *) (Processed_audio), AUDIO_BLOCK_SIZE); //memcpy((uint16_t *)(AUDIO_BUFFER_OUT + (AUDIO_BLOCK_SIZE)), (uint16_t *)(AUDIO_BUFFER_IN + (AUDIO_BLOCK_SIZE)), AUDIO_BLOCK_SIZE); /* Compute important cycle information and display it*/ sprintf(buf, "1:%6d 2:%6d T:%6d", first_half_time, second_half_time, total_time); BSP_LCD_SetTextColor(LCD_COLOR_RED); BSP_LCD_DisplayStringAt(0, 20, (uint8_t *) buf, LEFT_MODE); /* Copy recorded 2nd half block into audio output buffer */ /* Change the recording buffer state to reflect the status of the buffer */ audio_rec_buffer_state = BUFFER_OFFSET_NONE; /* Increase the counter */ counter++; /* Measures the amount of time to process the second half */ second_half_time = timer.read_us(); /* End Second Half */ } } /** * @brief Draws a trace of the data line. * @param Xpos: X position * @param Ypos: Y position * @param Mem_start: Start of memory location * @param Length: length of trace * @retval None */ void Erase_Trace(uint16_t Xpos, uint16_t Ypos, uint16_t Length) { BSP_LCD_SetTextColor(LCD_COLOR_BLACK); BSP_LCD_FillRect(Xpos, Ypos - AUDIO_DRAW_LIMIT, OSC_LINE_SIZE/2, AUDIO_DRAW_LIMIT); BSP_LCD_FillRect(Xpos, Ypos+1, OSC_LINE_SIZE/2, AUDIO_DRAW_LIMIT); } /** * @brief Draws a trace of the data line. * @param Xpos: X position * @param Ypos: Y position * @param Mem_start: Start of memory location * @param Length: length of trace * @retval None */ void Draw_Trace(uint16_t Xpos, uint16_t Ypos, uint16_t* Mem_start, uint16_t Length) { int16_t R; int16_t L; int16_t R_scaled; int16_t L_scaled; for(uint16_t ii = 0; ii < Length; ii++) { R = *Mem_start; Mem_start++; L = *Mem_start; Mem_start++; R_scaled = R/SCALE_FACTOR; L_scaled = L/SCALE_FACTOR; if(L_scaled != 0 && L_scaled < AUDIO_DRAW_LIMIT && L_scaled > -AUDIO_DRAW_LIMIT) { BSP_LCD_DrawPixel(ii + Xpos, L_scaled + Ypos, LCD_COLOR_BLUE); } if(R_scaled != 0 && R_scaled < AUDIO_DRAW_LIMIT && R_scaled > -AUDIO_DRAW_LIMIT) { BSP_LCD_DrawPixel(ii + Xpos, R_scaled + Ypos, LCD_COLOR_GREEN); } } } /** * @brief Converts audio data in buffer to floating point representation. * @param buffer_in: Pointer to Audio buffer start location * @param L_out: Pointer to Left channel out data (float) * @param R_out: Pointer to Right channel out data (float) * @param Length: length of data to convert * @retval None */ void Audio_to_Float(uint16_t* buffer_in, float* L_out, float* R_out, uint16_t Length) { int16_t R; int16_t L; for(uint16_t ii = 0; ii < Length; ii++) { R = *buffer_in; buffer_in++; L = *buffer_in; buffer_in++; *R_out = R; R_out++; *L_out = L; L_out++; } } /** * @brief Converts audio data in buffer to floating point representation. * @param L_out: Pointer to Left channel in data (float) * @param R_out: Pointer to Right channel in data (float) * @param buffer_out: Pointer to combined 32 bit (two 16-bit int samples) * @param Length: length of data to convert * @retval None */ void Float_to_Audio(float* L_in, float* R_in, uint16_t* buffer_out, uint16_t Length) { int16_t R; int16_t L; for(uint16_t ii = 0; ii < Length; ii++) { R = *R_in; R_in++; L = *L_in; L_in++; *buffer_out = R; buffer_out++; *buffer_out = L; buffer_out++; } } /*------------------------------------------------------------------------------------- Callbacks implementation: the callbacks API are defined __weak in the stm32746g_discovery_audio.c file and their implementation should be done in the user code if they are needed. Below some examples of callback implementations. -------------------------------------------------------------------------------------*/ /** * @brief Manages the DMA Transfer complete interrupt. * @param None * @retval None */ void BSP_AUDIO_IN_TransferComplete_CallBack(void) { audio_rec_buffer_state = BUFFER_OFFSET_FULL; } /** * @brief Manages the DMA Half Transfer complete interrupt. * @param None * @retval None */ void BSP_AUDIO_IN_HalfTransfer_CallBack(void) { audio_rec_buffer_state = BUFFER_OFFSET_HALF; } /** * @brief Audio IN Error callback function. * @param None * @retval None */ void BSP_AUDIO_IN_Error_CallBack(void) { printf("BSP_AUDIO_IN_Error_CallBack\n"); }