In continuation of my yesterday's article on Geektimes, I want to tell more about the implementation of digitizing and encoding sound on the STM32 microcontroller.Speex is a free speech compression codec that can be used in voice-over-the-Internet (VoIP) applications. Speex codec compressed data can be stored either in the Ogg audio data storage format or transmitted directly using UDP / RTP packets. © Wiki
In this article, I will use the cheapest and most common debugging board based on the STM32F103C8T6 microcontroller. To her must be separately purchased programmer. The approach will not change for any Discovery card. I connected to the debugging microphone module with amplifier Max9812.




Connect the Speex library#ifdef HAVE_CONFIG_H #include "config.h" #endif #include <speex/speex.h> #include "stm32f1xx_hal.h" #define FRAME_SIZE 160 //*0.125 = 20 ( 8) #define ENCODED_FRAME_SIZE 20 // 8 #define MAX_REC_FRAMES 90 // , = MAX_REC_FRAMES*0,02 extern __IO uint16_t IN_Buffer[2][FRAME_SIZE]; extern __IO uint8_t Start_Encoding; void Speex_Init(void); void EncodingVoice(void); #include "speexx.h" //SPEEX variables __IO uint16_t IN_Buffer[2][FRAME_SIZE]; __IO uint8_t Start_Encoding = 0; uint8_t Index_Encoding = 0; uint32_t Encoded_Frames = 0; uint8_t REC_DATA[2][MAX_REC_FRAMES*ENCODED_FRAME_SIZE]; // uint8_t* Rec_Data_ptr = &REC_DATA[0][0]; // uint8_t* Trm_Data_ptr; // int quality = 4, complexity=1, vbr=0, enh=1;/* SPEEX PARAMETERS, MUST REMAINED UNCHANGED */ SpeexBits bits; /* Holds bits so they can be read and written by the Speex routines */ void *enc_state, *dec_state;/* Holds the states of the encoder & the decoder */ void Speex_Init(void) { /* Speex encoding initializations */ speex_bits_init(&bits); enc_state = speex_encoder_init(&speex_nb_mode); speex_encoder_ctl(enc_state, SPEEX_SET_VBR, &vbr); speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY,&quality); speex_encoder_ctl(enc_state, SPEEX_SET_COMPLEXITY, &complexity); } void EncodingVoice(void) { uint8_t i; //==================== ====================== if(Start_Encoding > 0) { Index_Encoding = Start_Encoding - 1; for (i=0;i<FRAME_SIZE;i++) IN_Buffer[Index_Encoding][i]^=0x8000; /* Flush all the bits in the struct so we can encode a new frame */ speex_bits_reset(&bits); /* Encode the frame */ speex_encode_int(enc_state, (spx_int16_t*)IN_Buffer[Index_Encoding], &bits); /* Copy the bits to an array of char that can be decoded */ speex_bits_write(&bits, (char *)Rec_Data_ptr, ENCODED_FRAME_SIZE); Rec_Data_ptr += ENCODED_FRAME_SIZE; Encoded_Frames += 1; Start_Encoding = 0; } if (Encoded_Frames == MAX_REC_FRAMES) { __no_operation(); // , &REC_DATA[0][0] } if (Encoded_Frames == MAX_REC_FRAMES*2) { Rec_Data_ptr = &REC_DATA[0][0]; Encoded_Frames = 0; __no_operation(); // , &REC_DATA[1][0] } } void DMA1_Channel1_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */ if (DMA1->ISR & DMA_FLAG_HT1) { Start_Encoding = 1; } // DMA , if (DMA1->ISR & DMA_FLAG_TC1) { Start_Encoding = 2; } // DMA , /* USER CODE END DMA1_Channel1_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_adc1); /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */ /* USER CODE END DMA1_Channel1_IRQn 1 */ } /** * @brief This function handles TIM3 global interrupt. */ void TIM3_IRQHandler(void) { /* USER CODE BEGIN TIM3_IRQn 0 */ HAL_NVIC_ClearPendingIRQ(TIM3_IRQn); /* USER CODE END TIM3_IRQn 0 */ HAL_TIM_IRQHandler(&htim3); /* USER CODE BEGIN TIM3_IRQn 1 */ /* USER CODE END TIM3_IRQn 1 */ } Speex_Init(); if(HAL_TIM_Base_Start_IT(&htim3) != HAL_OK) Error_Handler(); if(HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&IN_Buffer[0],FRAME_SIZE*2) != HAL_OK) Error_Handler(); while (1) { EncodingVoice(); } HAL_NVIC_ClearPendingIRQ(TIM3_IRQn); if (DMA1->ISR & DMA_FLAG_HT1) { Start_Encoding = 1; } if (DMA1->ISR & DMA_FLAG_TC1) { Start_Encoding = 2; } #define FRAME_SIZE 160 //*0.125 = 20 ( 8) #define ENCODED_FRAME_SIZE 20 // #define MAX_REC_FRAMES 90 // , = MAX_REC_FRAMES*0,02 int quality = 4, complexity=1, vbr=0, enh=1;/* SPEEX PARAMETERS, MUST REMAINED UNCHANGED */ Source: https://habr.com/ru/post/323598/
All Articles