R&J / Mbed 2 deprecated 487_Laboratory_3

Dependencies:   mbed BSP_DISCO_F746NG mbed-dsp

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /**
00002   ******************************************************************************
00003   * @file    main.c
00004   * @author  Brian Mazzeo
00005   * @date    2020
00006   * @brief   This file provides a set of code for signal processing in 487.
00007   *          Parts are taken from example code from STMIcroelectronics
00008   ******************************************************************************
00009   * @attention
00010   *          This code was specifically developed for BYU ECEn 487 course 
00011   *          Introduction to Digital Signal Processing.
00012   *
00013   *
00014   ******************************************************************************
00015   */ 
00016 
00017 
00018 #include "mbed.h"
00019 #include "stm32746g_discovery_audio.h"
00020 #include "stm32746g_discovery_sdram.h"
00021 #include "stm32746g_discovery_lcd.h"
00022 #include "arm_math.h"
00023 #include "signal_processing.h"
00024 #include "spectrum.h"
00025 
00026 /* The following type definitions are used to control the 
00027  * buffering of the audio data using a double buffering technique.
00028  * Most of the transactions between the WM8994 and the microcontroller
00029  * are handled by other code - but this signals what the buffering state
00030  * is, so the data can be appropriately processed. */
00031 typedef enum {
00032     BUFFER_OFFSET_NONE = 0,
00033     BUFFER_OFFSET_HALF = 1,
00034     BUFFER_OFFSET_FULL = 2,
00035 } BUFFER_StateTypeDef;
00036 
00037 /* These audio block samples define the size of the buffering */
00038 #define AUDIO_BLOCK_SAMPLES             ((uint32_t)128)         // Number of samples (L and R) in audio block (each samples is 16 bits)
00039 #define AUDIO_BLOCK_SIZE                ((uint32_t)512)         // Number of bytes in audio block (4 * AUDIO_BLOCK_SAMPLES)
00040 
00041 /* These RAM addresses are important to determine where the audio data is stored. */
00042 #define SDRAM_DEVICE_ADDR_AUDIO_MEM     ((uint32_t)0xC0400000)
00043 #define AUDIO_BUFFER_IN                 SDRAM_DEVICE_ADDR_AUDIO_MEM
00044 #define AUDIO_BUFFER_OUT                (AUDIO_BUFFER_IN + (AUDIO_BLOCK_SIZE * 2))
00045 
00046 /* These definitions define the size of the oscilloscope that is used to display data. */
00047 #define OSC_START_X_POS     20
00048 #define OSC_LINE_SIZE       256
00049 #define OSC_Y_POS           130
00050 #define AUDIO_DRAW_LIMIT    50
00051 
00052 /* This define a timer that is then used to record the timing of the different processing stages. */
00053 Timer timer;
00054 
00055 /* This variable is important because it define the audio buffer recording state. */
00056 volatile uint32_t  audio_rec_buffer_state = BUFFER_OFFSET_NONE;
00057 
00058 /* Function declarations */
00059 static void Erase_Trace(uint16_t Xpos, uint16_t Ypos, uint16_t Length);
00060 static void Draw_Trace(uint16_t Xpos, uint16_t Ypos, uint16_t* Mem_start, uint16_t Length);
00061 static void Audio_to_Float(uint16_t* buffer_in, float32_t* L_out, float32_t* R_out, uint16_t Length);
00062 static void Float_to_Audio(float32_t* L_in, float32_t* R_in, uint16_t* buffer_out, uint16_t Length);
00063 
00064 /* These memory blocks are important for converting to floating point representation. */
00065 float32_t       L_channel_float_in[AUDIO_BLOCK_SAMPLES];
00066 float32_t       R_channel_float_in[AUDIO_BLOCK_SAMPLES];
00067 float32_t       L_channel_float_out[AUDIO_BLOCK_SAMPLES];
00068 float32_t       R_channel_float_out[AUDIO_BLOCK_SAMPLES];
00069 float32_t       *L_channel_float_in_p = &L_channel_float_in[0];
00070 float32_t       *R_channel_float_in_p = &R_channel_float_in[0];
00071 float32_t       *L_channel_float_out_p = &L_channel_float_out[0];
00072 float32_t       *R_channel_float_out_p = &R_channel_float_out[0];
00073 
00074 /* These memory blocks are where the information is stored to send back out to the WM8994 chip. */
00075 uint16_t    Processed_audio[AUDIO_BLOCK_SAMPLES];
00076 uint16_t    *Processed_audio_p = &Processed_audio[0];
00077 
00078 /* Useful variables during looping */
00079 uint32_t counter = 0;               // Loop counter
00080 char buf[40];                       // Character buffer for sprintf statements to the LCD
00081 int first_half_time = 0;            // Time of first processing block
00082 int second_half_time = 0;           // Time of second processing block
00083 int total_time = 0;                 // Time of total loop (first and second blocks)
00084 
00085 /* Main Function */
00086 int main()
00087 {
00088     /* Initialize the LCD Screen and display information */    
00089     BSP_LCD_Init();
00090     BSP_LCD_LayerDefaultInit(LTDC_ACTIVE_LAYER, LCD_FB_START_ADDRESS);
00091     BSP_LCD_SelectLayer(LTDC_ACTIVE_LAYER);
00092 
00093     /* Clear the LCD and set the font to be default */
00094     BSP_LCD_Clear(LCD_COLOR_BLACK);
00095     BSP_LCD_SetFont(&LCD_DEFAULT_FONT);
00096     
00097     /* Set the backcolor to be black and the textcolor to be orange. */    
00098     BSP_LCD_SetBackColor(LCD_COLOR_BLACK);
00099     BSP_LCD_SetTextColor(LCD_COLOR_ORANGE);
00100     
00101     /* The following are static display elements that will remain on the screen. */
00102     BSP_LCD_DisplayStringAt(0, 0, (uint8_t *)"487 Demo Code (Mazzeo)", LEFT_MODE);
00103     
00104     /* Display the L and R colors for the channels */
00105     BSP_LCD_SetTextColor(LCD_COLOR_BLUE);
00106     BSP_LCD_DisplayStringAt(0, OSC_Y_POS - 20, (uint8_t *)"L", LEFT_MODE);
00107     BSP_LCD_SetTextColor(LCD_COLOR_GREEN);
00108     BSP_LCD_DisplayStringAt(0, OSC_Y_POS, (uint8_t *)"R", LEFT_MODE);
00109     
00110     //Set up the spectrum background display
00111     Draw_Spectrum_Background();
00112 
00113     /* The following code should not be code that you need to worry about - it sets up the audio interfaces. */
00114         /* Initialize the Audio Interface */
00115         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);
00116     
00117         /* Initialize SDRAM buffers */
00118         BSP_SDRAM_Init();
00119         memset((uint16_t *)AUDIO_BUFFER_IN, 0, AUDIO_BLOCK_SIZE * 2);
00120         memset((uint16_t *)AUDIO_BUFFER_OUT, 0, AUDIO_BLOCK_SIZE * 2);
00121     
00122         /* Start Recording */
00123         if (BSP_AUDIO_IN_Record((uint16_t *)AUDIO_BUFFER_IN, AUDIO_BLOCK_SIZE) != AUDIO_OK) { printf("BSP_AUDIO_IN_Record error\n"); }
00124     
00125         /* Start Playback */
00126         BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_02);
00127         if (BSP_AUDIO_OUT_Play((uint16_t *)AUDIO_BUFFER_OUT, AUDIO_BLOCK_SIZE * 2) != AUDIO_OK) { printf("BSP_AUDIO_OUT_Play error\n"); }
00128         
00129     /* The audio interfaces are all now working.
00130      * Importantly - AUDIO_BUFFER_IN is the pointer to the incoming data from the WM8994
00131      *               AUDIO_BUFFER_OUT is the pointer to the outgoing data to the WM8994 */
00132 
00133 
00134     /* Initialize signal processing filters - usually there are variables that
00135      * need to be set up or that there are arrays you need to precompute - this
00136      * function call allows you to do that. */
00137     initalize_signal_processing();
00138 
00139     /* Hardware timer starts. Set to zero */
00140     timer.start();
00141     
00142     /* Main signal processing while loop */
00143     while (1) {
00144     
00145     /* First Half */
00146         /* Wait until end of half block recording before going on in the first half cycle*/
00147         while (audio_rec_buffer_state != BUFFER_OFFSET_HALF) {}
00148 
00149         /* This captures the time of an entire cycle */
00150         total_time = timer.read_us();
00151         
00152         /* Reset the timer counter to zero */
00153         timer.reset();
00154 
00155         /* Plot traces of first half block recording */   
00156         Erase_Trace(OSC_START_X_POS, OSC_Y_POS, AUDIO_BLOCK_SAMPLES);
00157         Draw_Trace(OSC_START_X_POS, OSC_Y_POS, (uint16_t *) AUDIO_BUFFER_IN, AUDIO_BLOCK_SAMPLES);
00158         
00159         
00160         
00161         /* Convert data to floating point representation for processing */
00162         Audio_to_Float((uint16_t *) AUDIO_BUFFER_IN, L_channel_float_in_p, R_channel_float_in_p, AUDIO_BLOCK_SAMPLES);
00163 
00164             /* ------------------------------------------------------------------------ */
00165             /* Here is where signal processing can be done on the floating point arrays */
00166 
00167             process_audio_channel_signals(L_channel_float_in_p, R_channel_float_in_p, L_channel_float_out_p, R_channel_float_out_p, AUDIO_BLOCK_SAMPLES);
00168             FFT_audio_input(L_channel_float_in_p, R_channel_float_in_p, AUDIO_BLOCK_SAMPLES);
00169         
00170             /* Here is where signal processing can end on the floating point arrays */        
00171             /* -------------------------------------------------------------------- */    
00172                 
00173         /* Covert floating point data back to fixed point audio format */
00174         Float_to_Audio(L_channel_float_out_p, R_channel_float_out_p, (uint16_t *) Processed_audio, AUDIO_BLOCK_SAMPLES);
00175 
00176         /* Copy recorded 1st half block into the audio buffer that goes out */
00177         /* Replace the second memcpy with this first one once you have worked out the processed audio functions. */
00178         memcpy((uint16_t *)(AUDIO_BUFFER_OUT), (uint16_t *)(Processed_audio), AUDIO_BLOCK_SIZE);
00179         //memcpy((uint16_t *)(AUDIO_BUFFER_OUT), (uint16_t *)(AUDIO_BUFFER_IN), AUDIO_BLOCK_SIZE);
00180 
00181         /* Display useful cycle information (split up information display so the processing is more balanced) */
00182         sprintf(buf, "Cycles: %9d", counter);
00183         BSP_LCD_SetTextColor(LCD_COLOR_RED);
00184         BSP_LCD_DisplayStringAt(0, 46, (uint8_t *) buf, LEFT_MODE);                
00185 
00186 
00187         /* Capture the timing of the first half processing */
00188         first_half_time = timer.read_us();
00189     /* End First Half */
00190 
00191     /* Second Half */
00192         /* Wait end of one block recording */
00193         while (audio_rec_buffer_state != BUFFER_OFFSET_FULL) {}
00194         
00195         /* Plot traces of second half block recording */
00196         Erase_Trace(OSC_START_X_POS+AUDIO_BLOCK_SAMPLES, OSC_Y_POS, AUDIO_BLOCK_SAMPLES);
00197         Draw_Trace( OSC_START_X_POS+AUDIO_BLOCK_SAMPLES, OSC_Y_POS, (uint16_t *) (AUDIO_BUFFER_IN + (AUDIO_BLOCK_SIZE)), AUDIO_BLOCK_SAMPLES);
00198 
00199         /* Convert data to floating point representation for processing */
00200         Audio_to_Float((uint16_t *) (AUDIO_BUFFER_IN + (AUDIO_BLOCK_SIZE)), L_channel_float_in_p, R_channel_float_in_p, AUDIO_BLOCK_SAMPLES);
00201 
00202             /* ------------------------------------------------------------------------ */
00203             /* Here is where signal processing can be done on the floating point arrays */
00204 
00205             process_audio_channel_signals(L_channel_float_in_p, R_channel_float_in_p, L_channel_float_out_p, R_channel_float_out_p, AUDIO_BLOCK_SAMPLES);
00206             FFT_audio_input(L_channel_float_in_p, R_channel_float_in_p, AUDIO_BLOCK_SAMPLES);
00207         
00208             /* Here is where signal processing can end on the floating point arrays */        
00209             /* -------------------------------------------------------------------- */    
00210             
00211         /* Covert floating point data back to fixed point audio format */
00212         Float_to_Audio(L_channel_float_out_p, R_channel_float_out_p, (uint16_t *) Processed_audio, AUDIO_BLOCK_SAMPLES);
00213 
00214         /* Copy recorded 2nd half block into the audio buffer that goes out */
00215         memcpy((uint16_t *)(AUDIO_BUFFER_OUT + (AUDIO_BLOCK_SIZE)), (uint16_t *) (Processed_audio), AUDIO_BLOCK_SIZE);
00216         //memcpy((uint16_t *)(AUDIO_BUFFER_OUT + (AUDIO_BLOCK_SIZE)), (uint16_t *)(AUDIO_BUFFER_IN + (AUDIO_BLOCK_SIZE)), AUDIO_BLOCK_SIZE);
00217         
00218                 
00219         /* Compute important cycle information and display it*/
00220         sprintf(buf, "1:%6d 2:%6d T:%6d", first_half_time, second_half_time, total_time);
00221         BSP_LCD_SetTextColor(LCD_COLOR_RED);
00222         BSP_LCD_DisplayStringAt(0, 20, (uint8_t *) buf, LEFT_MODE);
00223 
00224         /* Copy recorded 2nd half block into audio output buffer */
00225             
00226         /* Change the recording buffer state to reflect the status of the buffer */   
00227         audio_rec_buffer_state = BUFFER_OFFSET_NONE;
00228 
00229         /* Increase the counter */
00230         counter++;
00231         
00232         /* Measures the amount of time to process the second half */    
00233         second_half_time = timer.read_us();
00234         
00235     /* End Second Half */
00236     }
00237 }
00238 
00239 /**
00240   * @brief  Draws a trace of the data line.
00241   * @param  Xpos: X position
00242   * @param  Ypos: Y position
00243   * @param  Mem_start: Start of memory location
00244   * @param  Length: length of trace
00245   * @retval None
00246   */
00247 void Erase_Trace(uint16_t Xpos, uint16_t Ypos, uint16_t Length)
00248 {
00249     /* Creates a brown rectangle above and below the axis */
00250     BSP_LCD_SetTextColor(LCD_COLOR_BROWN);
00251     BSP_LCD_FillRect(Xpos, Ypos - AUDIO_DRAW_LIMIT, Length, AUDIO_DRAW_LIMIT);
00252     BSP_LCD_FillRect(Xpos, Ypos+1, Length, AUDIO_DRAW_LIMIT);
00253     
00254     /* Draw axis for plotting */
00255     BSP_LCD_SetTextColor(LCD_COLOR_WHITE);
00256     BSP_LCD_DrawHLine(Xpos, Ypos, Length);
00257 
00258 }
00259 
00260 
00261 /**
00262   * @brief  Draws a trace of the data line.
00263   * @param  Xpos: X position
00264   * @param  Ypos: Y position
00265   * @param  Mem_start: Start of memory location
00266   * @param  Length: length of trace
00267   * @retval None
00268   */
00269 void Draw_Trace(uint16_t Xpos, uint16_t Ypos, uint16_t* Mem_start, uint16_t Length)
00270 {
00271     uint16_t i;
00272     uint16_t* mem_address;
00273     char buf[10];
00274     int16_t L_audio_value;
00275     int16_t R_audio_value;
00276        
00277     mem_address = Mem_start;
00278       
00279     for (i=0; i<Length; i++)
00280    {       
00281         R_audio_value = (int16_t) *mem_address;
00282         mem_address++;
00283         L_audio_value = (int16_t) *mem_address;
00284         mem_address++;
00285         
00286         L_audio_value = L_audio_value / 100;
00287         R_audio_value = R_audio_value / 100;
00288         
00289         if (L_audio_value > AUDIO_DRAW_LIMIT) {L_audio_value = AUDIO_DRAW_LIMIT;}
00290         else if (L_audio_value < -AUDIO_DRAW_LIMIT) {L_audio_value = -AUDIO_DRAW_LIMIT;}
00291 
00292         if (R_audio_value > AUDIO_DRAW_LIMIT) {R_audio_value = AUDIO_DRAW_LIMIT;}
00293         else if (R_audio_value < -AUDIO_DRAW_LIMIT) {R_audio_value = -AUDIO_DRAW_LIMIT;}
00294         
00295         BSP_LCD_DrawPixel(Xpos + i, (uint16_t) ((int16_t) Ypos + L_audio_value), LCD_COLOR_BLUE);
00296         BSP_LCD_DrawPixel(Xpos + i, (uint16_t) ((int16_t) Ypos + R_audio_value), LCD_COLOR_GREEN);
00297    }
00298    
00299 }
00300 
00301 
00302 
00303 
00304 
00305 
00306 
00307 /**
00308   * @brief  Converts audio data in buffer to floating point representation.
00309   * @param  buffer_in: Pointer to Audio buffer start location
00310   * @param  L_out: Pointer to Left channel out data (float32_t)
00311   * @param  R_out: Pointer to Right channel out data (float32_t)
00312   * @param  Length: length of data to convert
00313   * @retval None
00314   */
00315 void Audio_to_Float(uint16_t* buffer_in, float32_t* L_out, float32_t* R_out, uint16_t Length)
00316 {
00317     uint16_t i;
00318     uint16_t* audio_mem_address;
00319     float32_t* L_chan_mem_address;
00320     float32_t* R_chan_mem_address;
00321     float32_t L_audio_value;
00322     float32_t R_audio_value;
00323 
00324     audio_mem_address = buffer_in;
00325     L_chan_mem_address = L_out;
00326     R_chan_mem_address = R_out;
00327     
00328     for (i=0; i<Length; i++)
00329    {
00330         R_audio_value = (float32_t) ((int16_t) *audio_mem_address);
00331         audio_mem_address++;
00332         L_audio_value = (float32_t) ((int16_t) *audio_mem_address);
00333         audio_mem_address++;
00334                 
00335         *L_chan_mem_address = L_audio_value;
00336         L_chan_mem_address++;
00337         
00338         *R_chan_mem_address = R_audio_value;
00339         R_chan_mem_address++;
00340    }
00341 }
00342 
00343 /**
00344   * @brief  Converts audio data in buffer to floating point representation.
00345   * @param  L_out: Pointer to Left channel in data (float32_t)
00346   * @param  R_out: Pointer to Right channel in data (float32_t)
00347   * @param  buffer_out: Pointer to combined 32 bit (two 16-bit int samples)
00348   * @param  Length: length of data to convert
00349   * @retval None
00350   */
00351 void Float_to_Audio(float32_t* L_in, float32_t* R_in, uint16_t* buffer_out, uint16_t Length)
00352 {
00353     uint16_t i;
00354     uint16_t* audio_mem_address;
00355     float32_t* L_chan_mem_address;
00356     float32_t* R_chan_mem_address;
00357     int16_t L_audio_value;
00358     int16_t R_audio_value;
00359         
00360     audio_mem_address = buffer_out;
00361     L_chan_mem_address = L_in;
00362     R_chan_mem_address = R_in;
00363     
00364     for (i=0; i<Length; i++)
00365    {
00366         L_audio_value = (int16_t) ((float32_t) *L_chan_mem_address);
00367         L_chan_mem_address++;
00368         
00369         R_audio_value = (int16_t) ((float32_t) *R_chan_mem_address);
00370         R_chan_mem_address++;
00371         
00372         *audio_mem_address = (uint16_t) R_audio_value;
00373         audio_mem_address++;
00374         *audio_mem_address = (uint16_t) L_audio_value;
00375         audio_mem_address++;
00376    }
00377 }
00378 
00379 
00380 
00381 
00382 
00383 /*-------------------------------------------------------------------------------------
00384        Callbacks implementation:
00385            the callbacks API are defined __weak in the stm32746g_discovery_audio.c file
00386            and their implementation should be done in the user code if they are needed.
00387            Below some examples of callback implementations.
00388   -------------------------------------------------------------------------------------*/
00389 /**
00390   * @brief Manages the DMA Transfer complete interrupt.
00391   * @param None
00392   * @retval None
00393   */
00394 void BSP_AUDIO_IN_TransferComplete_CallBack(void)
00395 {
00396     audio_rec_buffer_state = BUFFER_OFFSET_FULL;
00397 }
00398 
00399 /**
00400   * @brief  Manages the DMA Half Transfer complete interrupt.
00401   * @param  None
00402   * @retval None
00403   */
00404 void BSP_AUDIO_IN_HalfTransfer_CallBack(void)
00405 {
00406     audio_rec_buffer_state = BUFFER_OFFSET_HALF;
00407 }
00408 
00409 /**
00410   * @brief  Audio IN Error callback function.
00411   * @param  None
00412   * @retval None
00413   */
00414 void BSP_AUDIO_IN_Error_CallBack(void)
00415 {
00416     printf("BSP_AUDIO_IN_Error_CallBack\n");
00417 }