2025-03-18 10:54:44 +01:00

198 lines
5.8 KiB
C

#include "audio.h"
#include "cmsis_os2.h"
#include "standard_output/standard_output.h"
#include <pdm2pcm_glo.h>
#include <stdbool.h>
#include <stm32h7xx_hal.h>
#include <string.h>
static SAI_HandleTypeDef sai;
static DMA_HandleTypeDef dma;
static uint8_t rx_buf[ACQUISITION_LENGTH * 4] __attribute__((section(".SAISection"))) = {0};
static PDM_Filter_Handler_t pdm_fh;
static PDM_Filter_Config_t pdm_fc;
static osThreadId_t th;
static osEventFlagsId_t flags;
#define AUDIO_RECEPTION_DONE (0x01)
void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai) {
__HAL_RCC_BDMA_CLK_ENABLE();
// link BDMA0 to SAI4 RX
dma.Instance = BDMA_Channel0;
dma.Init.Request = BDMA_REQUEST_SAI4_A;
dma.Init.Direction = DMA_PERIPH_TO_MEMORY;
dma.Init.PeriphInc = DMA_PINC_DISABLE;
dma.Init.MemInc = DMA_MINC_ENABLE;
dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
dma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
dma.Init.Mode = DMA_NORMAL;
dma.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&dma);
__HAL_LINKDMA(&sai, hdmarx, dma);
//__HAL_LINKDMA(&sai, hdmatx, dma);
HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 12, 0);
HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn);
}
void BDMA_Channel0_IRQHandler() {
HAL_DMA_IRQHandler(&dma);
}
void SAI4_IRQHandler() {
HAL_SAI_IRQHandler(&sai);
}
static void sai_rx_cplt_cb(SAI_HandleTypeDef *sai) {
osEventFlagsSet(flags, AUDIO_RECEPTION_DONE);
}
static void sai_init() {
__HAL_RCC_SAI4_CLK_ENABLE();
__HAL_RCC_SAI4_CLKAM_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
// initialize pins
GPIO_InitTypeDef gpio;
gpio.Pin = GPIO_PIN_5;
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_LOW;
gpio.Alternate = GPIO_AF10_SAI4;
HAL_GPIO_Init(GPIOE, &gpio);
gpio.Pin = GPIO_PIN_4;
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_LOW;
gpio.Alternate = GPIO_AF10_SAI4;
HAL_GPIO_Init(GPIOE, &gpio);
// initialize SAI4
memset(&sai, 0, sizeof(SAI_HandleTypeDef));
sai.Instance = SAI4_Block_A;
sai.Init.Protocol = SAI_FREE_PROTOCOL;
sai.Init.AudioMode = SAI_MODEMASTER_RX;
sai.Init.DataSize = SAI_DATASIZE_8;
sai.Init.FirstBit = SAI_FIRSTBIT_MSB;
sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE;
sai.Init.Synchro = SAI_ASYNCHRONOUS;
sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLED;
sai.Init.NoDivider = SAI_MASTERDIVIDER_DISABLE;
sai.Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE;
sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_FULL;
sai.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_16K;
sai.Init.MonoStereoMode = SAI_STEREOMODE;
sai.Init.CompandingMode = SAI_NOCOMPANDING;
sai.Init.PdmInit.Activation = ENABLE;
sai.Init.PdmInit.MicPairsNbr = 2; // 2
sai.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK2_ENABLE;
sai.FrameInit.FrameLength = 32; // 32
sai.FrameInit.ActiveFrameLength = 1;
sai.FrameInit.FSDefinition = SAI_FS_STARTFRAME;
sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_HIGH;
sai.FrameInit.FSOffset = SAI_FS_FIRSTBIT;
sai.SlotInit.FirstBitOffset = 0;
sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
sai.SlotInit.SlotNumber = 4; // 4
sai.SlotInit.SlotActive = 0x000F; // F
if (HAL_SAI_Init(&sai) != HAL_OK) {
MSG("Hiba a SAI4 inicializációjánál!\n");
}
HAL_SAI_RegisterCallback(&sai, HAL_SAI_RX_COMPLETE_CB_ID, sai_rx_cplt_cb);
SAI_Block_TypeDef *inst = sai.Instance;
MODIFY_REG(inst->CR1, SAI_xCR1_MCKDIV, 1 << SAI_xCR1_MCKDIV_Pos);
//__HAL_SAI_ENABLE(&sai);
HAL_NVIC_SetPriority(SAI4_IRQn, 12, 0);
HAL_NVIC_EnableIRQ(SAI4_IRQn);
// clear sample buffers
memset(rx_buf, 0, sizeof(uint32_t) * ACQUISITION_LENGTH);
}
// initialize PDM2PCM library
static void pdm2pcm_init() {
pdm_fh.bit_order = PDM_FILTER_BIT_ORDER_LSB;
pdm_fh.endianness = PDM_FILTER_ENDIANNESS_LE;
pdm_fh.high_pass_tap = 2104533974;
pdm_fh.in_ptr_channels = 1;
pdm_fh.out_ptr_channels = 1;
uint32_t status;
if ((status = PDM_Filter_Init(&pdm_fh)) != 0) {
MSG("PDM init error: %u\n", status);
}
pdm_fc.decimation_factor = PDM_FILTER_DEC_FACTOR_64;
pdm_fc.output_samples_number = 1024;
pdm_fc.mic_gain = 0;
if ((status = PDM_Filter_setConfig(&pdm_fh, &pdm_fc)) != 0) {
MSG("PDM config error: %u\n", status);
}
}
static uint8_t input[ACQUISITION_LENGTH];
static int16_t output[ACQUISITION_LENGTH];
static void thread_audio(void *arg) {
while (true) {
uint32_t signals = osEventFlagsWait(flags, AUDIO_RECEPTION_DONE, osFlagsWaitAny, osWaitForever);
if (signals & AUDIO_RECEPTION_DONE) {
// initialize the filter algorithm
uint32_t status;
// extract CH2R samples
for (uint16_t i = 0; i < ACQUISITION_LENGTH; i++) {
input[i] = rx_buf[2 + 4 * i];
}
// filter the samples
if ((status = PDM_Filter(input, output, &pdm_fh)) != 0) {
MSG("PDM filter error: %u\n", status);
}
}
}
}
void thread_init() {
// create event flags
flags = osEventFlagsNew(NULL);
// create new thread
osThreadAttr_t attr;
memset(&attr, 0, sizeof(osThreadAttr_t));
attr.stack_size = 4096;
attr.name = "audio";
th = osThreadNew(thread_audio, NULL, &attr);
if (th == NULL) {
MSG("Nem sikerült létrehozni a hangfeldolgozó folyamatot!\n");
}
}
void audio_init() {
sai_init();
pdm2pcm_init();
thread_init();
}
void audio_acquire() {
HAL_StatusTypeDef status;
if ((status = HAL_SAI_Receive_DMA(&sai, rx_buf, ACQUISITION_LENGTH * 4)) != HAL_OK) {
MSG("%s\n", (status == HAL_BUSY) ? "BUSY" : "ERROR");
}
}
void audio_print_output() {
for (uint16_t i = 0; i < 1024; i++) {
MSG("%d,", output[i]);
}
MSG("\n\n");
}