Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed BSP_DISCO_F746NG mbed-dsp
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 }
Generated on Mon Aug 1 2022 10:03:27 by
