From d11ce67189c929809e6a15b411e4c0978294c70c Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Tue, 16 Feb 2021 11:18:01 +0100 Subject: [PATCH 1/8] PDM: cleanup and fix --- libraries/PDM/src/stm32/PDM.cpp | 101 +- libraries/PDM/src/stm32/audio.c | 1812 +++-------------- libraries/PDM/src/stm32/audio.h | 362 +--- libraries/PDM/src/stm32/codec_api.h | 122 -- libraries/PDM/src/stm32/irq.c | 28 - libraries/PDM/src/stm32/wm8994.c | 1043 ---------- libraries/PDM/src/stm32/wm8994.h | 188 -- libraries/PDM/src/utility/PDMDoubleBuffer.cpp | 1 + libraries/PDM/src/utility/PDMDoubleBuffer.h | 2 +- 9 files changed, 304 insertions(+), 3355 deletions(-) delete mode 100644 libraries/PDM/src/stm32/codec_api.h delete mode 100644 libraries/PDM/src/stm32/irq.c delete mode 100644 libraries/PDM/src/stm32/wm8994.c delete mode 100644 libraries/PDM/src/stm32/wm8994.h diff --git a/libraries/PDM/src/stm32/PDM.cpp b/libraries/PDM/src/stm32/PDM.cpp index 0ad5feea4..b17548661 100644 --- a/libraries/PDM/src/stm32/PDM.cpp +++ b/libraries/PDM/src/stm32/PDM.cpp @@ -23,15 +23,12 @@ #ifdef TARGET_STM #include "PDM.h" -#include "audio.h" #include "mbed.h" +extern "C" { + #include "audio.h" +} -#define AUDIO_FREQUENCY BSP_AUDIO_FREQUENCY_16K -#define AUDIO_IN_PDM_BUFFER_SIZE (uint32_t)(128) - -//ALIGN_32BYTES (uint16_t recordPDMBuf[AUDIO_IN_PDM_BUFFER_SIZE]) __attribute__((section(".OPEN_AMP_SHMEM"))); -// FIXME: need to add an entry for RAM_D3 to linker script -uint16_t* recordPDMBuf = (uint16_t*)0x38000000; +extern "C" uint16_t *g_pcmbuf; PDMClass::PDMClass(int dinPin, int clkPin, int pwrPin) : _dinPin(dinPin), @@ -45,14 +42,10 @@ PDMClass::~PDMClass() { } -int PDMClass::begin(int channels, long sampleRate) { - - _channels = channels; - - // fixme: only works in stereo mode - channels = 2; +static int gain_db = -1; +static int _samplerate = -1; - setBufferSize(AUDIO_IN_PDM_BUFFER_SIZE / 4 * channels); +int PDMClass::begin(int channels, long sampleRate) { if (isBoardRev2()) { mbed::I2C i2c(PB_7, PB_6); @@ -69,43 +62,36 @@ int PDMClass::begin(int channels, long sampleRate) { i2c.write(8 << 1, data, sizeof(data)); } - BSP_AUDIO_IN_SelectInterface(AUDIO_IN_INTERFACE_PDM); + _channels = channels; + _samplerate = sampleRate; - /* Initialize audio IN at REC_FREQ*/ - if (BSP_AUDIO_IN_InitEx(INPUT_DEVICE_DIGITAL_MIC, AUDIO_FREQUENCY, DEFAULT_AUDIO_IN_BIT_RESOLUTION, channels) != AUDIO_OK) - { - return 0; + if (gain_db == -1) { + gain_db = -10; } - /* Start the record */ - BSP_AUDIO_IN_Record((uint16_t*)recordPDMBuf, AUDIO_IN_PDM_BUFFER_SIZE * channels); + //g_pcmbuf = (uint16_t*)_doubleBuffer.data(); + + py_audio_init(channels, sampleRate, gain_db, 0.9883f); + + py_audio_start_streaming(); + return 1; } void PDMClass::end() { + py_audio_stop_streaming(); + py_audio_deinit(); } int PDMClass::available() { size_t avail = _doubleBuffer.available(); - if (_channels == 1) { - return avail/2; - } else { - return avail; - } + return avail; } int PDMClass::read(void* buffer, size_t size) { - if (_channels == 1) { - uint16_t temp[size*2]; - int read = _doubleBuffer.read(temp, size*2); - for (int i = 0; i < size; i++) { - ((uint16_t*)buffer)[i] = temp[i*2]; - } - return read; - } int read = _doubleBuffer.read(buffer, size); return read; } @@ -117,7 +103,9 @@ void PDMClass::onReceive(void(*function)(void)) void PDMClass::setGain(int gain) { - + gain_db = gain; + //end(); + //begin(_channels, _samplerate); } void PDMClass::setBufferSize(int bufferSize) @@ -127,47 +115,26 @@ void PDMClass::setBufferSize(int bufferSize) void PDMClass::IrqHandler(bool halftranfer) { - - int start = halftranfer ? 0 : AUDIO_IN_PDM_BUFFER_SIZE; - - if (BSP_AUDIO_IN_GetInterface() == AUDIO_IN_INTERFACE_PDM && _doubleBuffer.available() == 0) { - - /* Invalidate Data Cache to get the updated content of the SRAM*/ - SCB_InvalidateDCache_by_Addr((uint32_t *)&recordPDMBuf[start], AUDIO_IN_PDM_BUFFER_SIZE * 2); - - //memcpy((uint16_t*)_doubleBuffer.data(), (uint16_t*)&recordPDMBuf[start], AUDIO_IN_PDM_BUFFER_SIZE/2); - BSP_AUDIO_IN_PDMToPCM((uint16_t*)&recordPDMBuf[start], (uint16_t*)_doubleBuffer.data()); - - /* Clean Data Cache to update the content of the SRAM */ - SCB_CleanDCache_by_Addr((uint32_t*)_doubleBuffer.data(), AUDIO_IN_PDM_BUFFER_SIZE * 2); - + if (_doubleBuffer.available() == 0) { + g_pcmbuf = (uint16_t*)_doubleBuffer.data(); + audio_pendsv_callback(); _doubleBuffer.swap(_doubleBuffer.availableForWrite()); } + if (_onReceive) { _onReceive(); } } extern "C" { - /** - @brief Calculates the remaining file size and new position of the pointer. - @param None - @retval None - */ - __attribute__((__used__)) void BSP_AUDIO_IN_TransferComplete_CallBack(void) - { - PDM.IrqHandler(false); - } +void PDMIrqHandler(bool halftranfer) +{ + PDM.IrqHandler(halftranfer); +} - /** - @brief Manages the DMA Half Transfer complete interrupt. - @param None - @retval None - */ - __attribute__((__used__)) void BSP_AUDIO_IN_HalfTransfer_CallBack(void) - { - PDM.IrqHandler(true); - } +void PDMsetBufferSize(int size) { + PDM.setBufferSize(size); +} } PDMClass PDM(0, 0, 0); diff --git a/libraries/PDM/src/stm32/audio.c b/libraries/PDM/src/stm32/audio.c index 84d33ce99..6878956dc 100644 --- a/libraries/PDM/src/stm32/audio.c +++ b/libraries/PDM/src/stm32/audio.c @@ -1,1659 +1,327 @@ -/** - ****************************************************************************** - * @file stm32h747i_discovery_audio.c - * @author MCD Application Team - * @brief This file provides the Audio driver for the STM32H747I-DISCOVERY - * board. - @verbatim - How To use this driver: - ----------------------- - + This driver supports STM32H7xx devices on STM32H747I-DISCOVERY (MB1248) Discovery boards. - + Call the function BSP_AUDIO_OUT_Init( - OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER, - OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH) - Volume : Initial volume to be set (0 is min (mute), 100 is max (100%) - AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...) - this parameter is relative to the audio file/stream type. - ) - This function configures all the hardware required for the audio application (codec, I2C, SAI, - GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK. - If the returned value is different from AUDIO_OK or the function is stuck then the communication with - the codec has failed (try to un-plug the power or reset device in this case). - - OUTPUT_DEVICE_SPEAKER : only speaker will be set as output for the audio stream. - - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream. - - OUTPUT_DEVICE_BOTH : both Speaker and Headphone are used as outputs for the audio stream - at the same time. - Note. On STM32H747I-DISCOVERY SAI_DMA is configured in CIRCULAR mode. Due to this the application - does NOT need to call BSP_AUDIO_OUT_ChangeBuffer() to assure streaming. - + Call the function BSP_AUDIO_OUT_Play( - pBuffer: pointer to the audio data file address - Size : size of the buffer to be sent in Bytes - ) - to start playing (for the first time) from the audio file/stream. - + Call the function BSP_AUDIO_OUT_Pause() to pause playing - + Call the function BSP_AUDIO_OUT_Resume() to resume playing. - Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called - for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case). - Note. This function should be called only when the audio file is played or paused (not stopped). - + For each mode, you may need to implement the relative callback functions into your code. - The Callback functions are named BSP_AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in - the stm32h747i_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) - + To Stop playing, to modify the volume level, the frequency, the audio frame slot, - the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(), - AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(), - BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop(). - - + Call the function BSP_AUDIO_IN_Init( - AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000...) - this parameter is relative to the audio file/stream type. - BitRes: Bit resolution fixed to 16bit - ChnlNbr: Number of channel to be configured for the DFSDM peripheral - ) - This function configures all the hardware required for the audio in application (channels, - Clock source for SAI PDM periphiral, GPIOs, DMA and interrupt if needed). - This function returns AUDIO_OK if configuration is OK.If the returned value is different from AUDIO_OK then - the configuration should be wrong. - + Call the function BSP_AUDIO_IN_AllocScratch( - pScratch: pointer to scratch tables - size: size of scratch buffer) - This function must be called before BSP_AUDIO_IN_RECORD() to allocate buffer scratch for each DFSDM channel - and its size. - Note: These buffers scratch are used as intermidiate buffers to collect data within final record buffer. - size is the total size of the four buffers scratch; If size is 512 then the size of each is 128. - This function must be called after BSP_AUDIO_IN_Init() - + Call the function BSP_AUDIO_IN_RECORD( - pBuf: pointer to the recorded audio data file address - Size: size of the buffer to be written in Bytes - ) - to start recording from microphones. - - + Call the function BSP_AUDIO_IN_Pause() to pause recording - + Call the function BSP_AUDIO_IN_Resume() to recording playing. - Note. After calling BSP_AUDIO_IN_Pause() function for pause, only BSP_AUDIO_IN_Resume() should be called - for resume (it is not allowed to call BSP_AUDIO_IN_RECORD() in this case). - + Call the function BSP_AUDIO_IN_Stop() to stop recording - + For each mode, you may need to implement the relative callback functions into your code. - The Callback functions are named BSP_AUDIO_IN_XXX_CallBack() and only their prototypes are declared in - the stm32h747i_discovery_audio.h file. (refer to the example for more details on the callbacks implementations) - + Call the function BSP_AUDIO_IN_SelectInterface(uint32_t Interface) to select one of the two interfaces - available on the STM32H747I-Discovery board: SAI or PDM. This function is to be called before BSP_AUDIO_IN_InitEx(). - + Call the function BSP_AUDIO_IN_GetInterface() to get the current used interface. - + Call the function BSP_AUDIO_IN_PDMToPCM_Init(uint32_t AudioFreq, uint32_t ChnlNbrIn, uint32_t ChnlNbrOut) - to init PDM filters if the libPDMFilter is used for audio data filtering. - + Call the function BSP_AUDIO_IN_PDMToPCM(uint16_t* PDMBuf, uint16_t* PCMBuf) to filter PDM data to PCM format - if the libPDMFilter library is used for audio data filtering. - - Driver architecture: - -------------------- - + This driver provides the High Audio Layer: consists of the function API exported in the stm32h747i_discovery_audio.h file - (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...) - + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/ - providing the audio file/stream. These functions are also included as local functions into - the stm32h747i_discovery_audio.c file (DFSDMx_Init(), DFSDMx_DeInit(), SAIx_Init() and SAIx_DeInit()) - - Known Limitations: - ------------------ - 1- If the TDM Format used to play in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second - Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams. - 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size, - File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file. - 3- Supports only Stereo audio streaming. - 4- Supports only 16-bits audio data size. - @endverbatim - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under BSD 3-Clause license, - * the "License"; You may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * opensource.org/licenses/BSD-3-Clause - * - ****************************************************************************** - */ - +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader + * Copyright (c) 2013-2021 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * Audio Python module. + */ #ifdef TARGET_STM -/* Includes ------------------------------------------------------------------*/ +#include +#include "stm32h7xx_hal.h" +#include "pdm2pcm_glo.h" #include "audio.h" +#include "stdbool.h" -/** @addtogroup BSP - * @{ - */ - -/** @addtogroup STM32H747I_DISCOVERY - * @{ - */ - -/** @defgroup STM32H747I_DISCOVERY_AUDIO STM32H747I_DISCOVERY_AUDIO - * @brief This file includes the low layer driver for wm8994 Audio Codec - * available on STM32H747I-DISCOVERY discovery board(MB1248). - * @{ - */ - -/** @defgroup STM32H747I_DISCOVERY_AUDIO_Private_Variables Private Variables - * @{ - */ -/* PLAY */ -AUDIO_DrvTypeDef *audio_drv; -SAI_HandleTypeDef haudio_out_sai; -SAI_HandleTypeDef haudio_in_sai; - -/* RECORD */ -AUDIOIN_ContextTypeDef hAudioIn; - - - -/* Audio in Volume value */ -__IO uint16_t AudioInVolume = DEFAULT_AUDIO_IN_VOLUME; - -/* PDM filters params */ -PDM_Filter_Handler_t PDM_FilterHandler[2]; -PDM_Filter_Config_t PDM_FilterConfig[2]; - -/** - * @} - */ +static CRC_HandleTypeDef hcrc; +static SAI_HandleTypeDef hsai; +static DMA_HandleTypeDef hdma_sai_rx; -/** @defgroup STM32H747I_DISCOVERY_AUDIO_Private_Function_Prototypes Private FunctionPrototypes - * @{ - */ -static void SAIx_Out_Init(uint32_t SaiOutMode, uint32_t SlotActive, uint32_t AudioFreq); -static void SAIx_Out_DeInit(SAI_HandleTypeDef *hsai); -static void SAIx_In_MspInit(SAI_HandleTypeDef *hsai, void *Params); -static void SAIx_In_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); -static void SAIx_In_Init(uint32_t SaiInMode, uint32_t SlotActive, uint32_t AudioFreq, bool mono); -static void SAIx_In_DeInit(SAI_HandleTypeDef *hsai); +volatile uint16_t *g_pcmbuf = NULL; -// TODO: this needs to become a library function -bool isBoardRev2() { - uint32_t hse_speed; - uint8_t* bootloader_data = (uint8_t*)(0x801F000); - if (bootloader_data[0] != 0xA0 || bootloader_data[1] < 14) { - hse_speed = 27000000; - } else { - hse_speed = bootloader_data[10] * 1000000; - } - return (hse_speed == 25000000); -} +static int g_channels = AUDIO_SAI_NBR_CHANNELS; +static PDM_Filter_Handler_t PDM_FilterHandler[2]; +static PDM_Filter_Config_t PDM_FilterConfig[2]; -/** - * @} - */ +#define DMA_XFER_NONE (0x00U) +#define DMA_XFER_HALF (0x01U) +#define DMA_XFER_FULL (0x04U) +static volatile uint32_t xfer_status = 0; -/** @defgroup STM32H747I_DISCOVERY_AUDIO_OUT_Exported_Functions OUT Exported Functions - * @{ - */ +// BDMA can only access D3 SRAM4 memory. +int8_t* PDM_BUFFER = (uint16_t*)0x38000000; -/** - * @brief Configures the audio Out peripheral. - * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, - * or OUTPUT_DEVICE_BOTH. - * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) - * @param AudioFreq: Audio frequency used to play the audio stream. - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq) -{ - uint8_t ret = AUDIO_ERROR; - uint32_t deviceid = 0x00; - uint32_t slot_active; - - /* Initialize SAI1 sub_block A as MASTER TX */ - haudio_out_sai.Instance = AUDIO_OUT_SAIx; - - /* Disable SAI */ - SAIx_Out_DeInit(&haudio_out_sai); - - /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ - BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); - - /* SAI data transfer preparation: - Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ - - if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) - { - /* Init the SAI MSP: this __weak function can be redefined by the application*/ - BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); - } - - /* Init SAI as master RX output */ - slot_active = CODEC_AUDIOFRAME_SLOT_0123; - SAIx_Out_Init(SAI_MODEMASTER_TX, slot_active, AudioFreq); - - /* wm8994 codec initialization */ - deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); - - if((deviceid) == WM8994_ID) - { - /* Reset the Codec Registers */ - wm8994_drv.Reset(AUDIO_I2C_ADDRESS); - /* Initialize the audio driver structure */ - audio_drv = &wm8994_drv; - ret = AUDIO_OK; - } - else - { - ret = AUDIO_ERROR; - } - - if(ret == AUDIO_OK) - { - /* Initialize the codec internal registers */ - audio_drv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq); - } - - return ret; -} - -/** - * @brief Starts playing audio stream from a data buffer for a determined size. - * @param pBuffer: Pointer to the buffer - * @param Size: Number of audio data BYTES. - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size) -{ - /* Call the audio Codec Play function */ - if(audio_drv->Play(AUDIO_I2C_ADDRESS, pBuffer, Size) != 0) - { - return AUDIO_ERROR; - } - else - { - /* Update the Media layer and enable it for play */ - HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE)); - - return AUDIO_OK; - } -} +void PDMIrqHandler(bool halftranfer); +void PDMsetBufferSize(int size); -/** - * @brief Sends n-Bytes on the SAI interface. - * @param pData: pointer on data address - * @param Size: number of data to be written - * @retval None - */ -void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size) +void AUDIO_SAI_DMA_IRQHandler(void) { - HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size); + HAL_DMA_IRQHandler(hsai.hdmarx); } -/** - * @brief This function Pauses the audio file stream. In case - * of using DMA, the DMA Pause feature is used. - * @warning When calling BSP_AUDIO_OUT_Pause() function for pause, only - * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() - * function for resume could lead to unexpected behaviour). - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_OUT_Pause(void) +void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) { - /* Call the Audio Codec Pause/Resume function */ - if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0) - { - return AUDIO_ERROR; - } - else - { - /* Call the Media layer pause function */ - HAL_SAI_DMAPause(&haudio_out_sai); - - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; - } + xfer_status |= DMA_XFER_HALF; + SCB_InvalidateDCache_by_Addr((uint32_t *)(&PDM_BUFFER[0]), PDM_BUFFER_SIZE / 2); + PDMIrqHandler(true); } -/** - * @brief Resumes the audio file stream. - * @warning When calling BSP_AUDIO_OUT_Pause() function for pause, only - * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play() - * function for resume could lead to unexpected behaviour). - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_OUT_Resume(void) +void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) { - /* Call the Audio Codec Pause/Resume function */ - if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0) - { - return AUDIO_ERROR; - } - else - { - /* Call the Media layer pause/resume function */ - HAL_SAI_DMAResume(&haudio_out_sai); - - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; - } + xfer_status |= DMA_XFER_FULL; + SCB_InvalidateDCache_by_Addr((uint32_t *)(&PDM_BUFFER[PDM_BUFFER_SIZE / 2]), PDM_BUFFER_SIZE / 2); + PDMIrqHandler(false); } -/** - * @brief Stops audio playing and Power down the Audio Codec. - * @param Option: could be one of the following parameters - * - CODEC_PDWN_SW: for software power off (by writing registers). - * Then no need to reconfigure the Codec after power on. - * - CODEC_PDWN_HW: completely shut down the codec (physically). - * Then need to reconfigure the Codec after power on. - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option) +static uint32_t get_decimation_factor(uint32_t decimation) { - /* Call the Media layer stop function */ - HAL_SAI_DMAStop(&haudio_out_sai); - - /* Call Audio Codec Stop function */ - if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0) - { - return AUDIO_ERROR; - } - else - { - if(Option == CODEC_PDWN_HW) - { - /* Wait at least 100us */ - HAL_Delay(1); + switch (decimation) { + case 16: return PDM_FILTER_DEC_FACTOR_16; + case 24: return PDM_FILTER_DEC_FACTOR_24; + case 32: return PDM_FILTER_DEC_FACTOR_32; + case 48: return PDM_FILTER_DEC_FACTOR_48; + case 64: return PDM_FILTER_DEC_FACTOR_64; + case 80: return PDM_FILTER_DEC_FACTOR_80; + case 128: return PDM_FILTER_DEC_FACTOR_128; + default: return 0; } - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; - } } -/** - * @brief Controls the current audio volume level. - * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for - * Mute and 100 for Max volume level). - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume) -{ - /* Call the codec volume control function with converted volume value */ - if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0) - { - return AUDIO_ERROR; - } - else - { - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; - } -} +#define AUDIO_FREQUENCY_192K ((uint32_t)192000) +#define AUDIO_FREQUENCY_96K ((uint32_t)96000) +#define AUDIO_FREQUENCY_48K ((uint32_t)48000) +#define AUDIO_FREQUENCY_44K ((uint32_t)44100) +#define AUDIO_FREQUENCY_32K ((uint32_t)32000) +#define AUDIO_FREQUENCY_22K ((uint32_t)22050) +#define AUDIO_FREQUENCY_16K ((uint32_t)16000) +#define AUDIO_FREQUENCY_11K ((uint32_t)11025) +#define AUDIO_FREQUENCY_8K ((uint32_t)8000) -/** - * @brief Enables or disables the MUTE mode by software - * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to - * unmute the codec and restore previous volume level. - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd) -{ - /* Call the Codec Mute function */ - if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0) - { - return AUDIO_ERROR; - } - else - { - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; - } -} - -/** - * @brief Switch dynamically (while audio file is played) the output target - * (speaker or headphone). - * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER, - * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output) -{ - /* Call the Codec output device function */ - if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0) - { - return AUDIO_ERROR; - } - else - { - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; +// TODO: this needs to become a library function +bool isBoardRev2() { + uint32_t hse_speed; + uint8_t* bootloader_data = (uint8_t*)(0x801F000); + if (bootloader_data[0] != 0xA0 || bootloader_data[1] < 14) { + hse_speed = 27000000; + } else { + hse_speed = bootloader_data[10] * 1000000; } + return (hse_speed == 25000000); } -/** - * @brief Updates the audio frequency. - * @param AudioFreq: Audio frequency used to play the audio stream. - * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the - * audio frequency. - * @retval None - */ -void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq) -{ - /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */ - BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL); - - /* Disable SAI peripheral to allow access to SAI internal registers */ - __HAL_SAI_DISABLE(&haudio_out_sai); - - /* Update the SAI audio frequency configuration */ - haudio_out_sai.Init.AudioFrequency = AudioFreq; - HAL_SAI_Init(&haudio_out_sai); - - /* Enable SAI peripheral to generate MCLK */ - __HAL_SAI_ENABLE(&haudio_out_sai); -} - -/** - * @brief Updates the Audio frame slot configuration. - * @param AudioFrameSlot: specifies the audio Frame slot - * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the - * audio frame slot. - * @retval None - */ -void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot) -{ - /* Disable SAI peripheral to allow access to SAI internal registers */ - __HAL_SAI_DISABLE(&haudio_out_sai); - - /* Update the SAI audio frame slot configuration */ - haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot; - HAL_SAI_Init(&haudio_out_sai); - - /* Enable SAI peripheral to generate MCLK */ - __HAL_SAI_ENABLE(&haudio_out_sai); -} - -/** - * @brief De-initializes the audio out peripheral. - * @retval None - */ -void BSP_AUDIO_OUT_DeInit(void) -{ - SAIx_Out_DeInit(&haudio_out_sai); - /* DeInit the SAI MSP : this __weak function can be rewritten by the application */ - BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL); -} - -/** - * @brief Manages the DMA full Transfer complete event. - * @retval None - */ -__weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void) -{ -} - -/** - * @brief Manages the DMA Half Transfer complete event. - * @retval None - */ -__weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void) -{ -} - -/** - * @brief Manages the DMA FIFO error event. - * @retval None - */ -__weak void BSP_AUDIO_OUT_Error_CallBack(void) -{ -} - -/** - * @brief Initializes BSP_AUDIO_OUT MSP. - * @param hsai: SAI handle - * @param Params: pointer on additional configuration parameters, can be NULL. - * @retval None - */ -__weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params) +void sai_init() { - static DMA_HandleTypeDef hdma_sai_tx; - GPIO_InitTypeDef gpio_init_structure; - - /* Enable SAI clock */ - AUDIO_OUT_SAIx_CLK_ENABLE(); - - /* CODEC_SAI pins configuration: FS, SCK and SD pins */ - /* Enable FS, SCK and SD clocks */ - AUDIO_OUT_SAIx_SD_FS_CLK_ENABLE(); - /* Enable FS, SCK and SD pins */ - gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN | AUDIO_OUT_SAIx_SCK_PIN | AUDIO_OUT_SAIx_SD_PIN; - gpio_init_structure.Mode = GPIO_MODE_AF_PP; - gpio_init_structure.Pull = GPIO_NOPULL; - gpio_init_structure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - gpio_init_structure.Alternate = AUDIO_OUT_SAIx_AF; - HAL_GPIO_Init(AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT, &gpio_init_structure); - - /* Enable MCLK clock */ - AUDIO_OUT_SAIx_MCLK_ENABLE(); - /* Enable MCLK pin */ - gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; - HAL_GPIO_Init(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, &gpio_init_structure); + GPIO_InitTypeDef GPIO_InitStruct; + AUDIO_SAI_CLK_ENABLE(); + __GPIOB_CLK_ENABLE(); + __GPIOE_CLK_ENABLE(); - /* Enable the DMA clock */ - AUDIO_OUT_SAIx_DMAx_CLK_ENABLE(); + GPIO_InitStruct.Pin = AUDIO_SAI_CK_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = AUDIO_SAI_CK_AF; + HAL_GPIO_Init(AUDIO_SAI_CK_PORT, &GPIO_InitStruct); - if(hsai->Instance == AUDIO_OUT_SAIx) - { - /* Configure the hdma_saiTx handle parameters */ - hdma_sai_tx.Init.Request = AUDIO_OUT_SAIx_DMAx_REQUEST; - hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; - hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE; - hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE; - hdma_sai_tx.Init.MemDataAlignment = AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE; - hdma_sai_tx.Init.Mode = DMA_CIRCULAR; - hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH; - hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; - hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE; - hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE; - - hdma_sai_tx.Instance = AUDIO_OUT_SAIx_DMAx_STREAM; - - /* Associate the DMA handle */ - __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx); - - /* Deinitialize the Stream for new transfer */ - HAL_DMA_DeInit(&hdma_sai_tx); - - /* Configure the DMA Stream */ - HAL_DMA_Init(&hdma_sai_tx); - } - - /* SAI DMA IRQ Channel configuration */ - HAL_NVIC_SetPriority(AUDIO_OUT_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0); - HAL_NVIC_EnableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); + GPIO_InitStruct.Pin = AUDIO_SAI_D1_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = AUDIO_SAI_D1_AF; + HAL_GPIO_Init(AUDIO_SAI_D1_PORT, &GPIO_InitStruct); } -/** - * @brief Deinitializes SAI MSP. - * @param hsai: SAI handle - * @param Params: pointer on additional configuration parameters, can be NULL. - * @retval None - */ -__weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params) +int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float highpass) { - GPIO_InitTypeDef gpio_init_structure; - - /* SAI DMA IRQ Channel deactivation */ - HAL_NVIC_DisableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ); - - if(hsai->Instance == AUDIO_OUT_SAIx) - { - /* Deinitialize the DMA stream */ - HAL_DMA_DeInit(hsai->hdmatx); - } - - /* Disable SAI peripheral */ - __HAL_SAI_DISABLE(hsai); - - /* Deactivates CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */ - gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN | AUDIO_OUT_SAIx_SCK_PIN | AUDIO_OUT_SAIx_SD_PIN; - HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT, gpio_init_structure.Pin); - gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN; - HAL_GPIO_DeInit(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, gpio_init_structure.Pin); + RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; - /* Disable SAI clock */ - AUDIO_OUT_SAIx_CLK_DISABLE(); + HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); - /* GPIO pins clock and DMA clock can be shut down in the applic - by surcharging this __weak function */ -} - -/** - * @brief Clock Config. - * @param hsai: might be required to set audio peripheral predivider if any. - * @param AudioFreq: Audio frequency used to play the audio stream. - * @param Params: pointer on additional configuration parameters, can be NULL. - * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency() - * Being __weak it can be overwritten by the application - * @retval None - */ -__weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params) -{ - RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; - - HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); - - /* Set the PLL configuration according to the audio frequency */ - if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) - { - /* SAI clock config: - PLL2_VCO Input = HSE_VALUE/PLL2M = 1 Mhz - PLL2_VCO Output = PLL2_VCO Input * PLL2N = 429 Mhz - SAI_CLK_x = PLL2_VCO Output/PLL2P = 429/38 = 11.289 Mhz */ - rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI1; - rcc_ex_clk_init_struct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL2; - rcc_ex_clk_init_struct.PLL2.PLL2P = 38; - rcc_ex_clk_init_struct.PLL2.PLL2Q = 1; - rcc_ex_clk_init_struct.PLL2.PLL2R = 1; - rcc_ex_clk_init_struct.PLL2.PLL2N = 429; - if (isBoardRev2()) { - rcc_ex_clk_init_struct.PLL2.PLL2M = 25; - } else { - rcc_ex_clk_init_struct.PLL2.PLL2M = 27; - } - HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); - } - else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */ - { /* SAI clock config: - PLL2_VCO Input = HSE_VALUE/PLL2M = 1 Mhz - PLL2_VCO Output = PLL2_VCO Input * PLL2N = 344 Mhz - SAI_CLK_x = PLL2_VCO Output/PLL2P = 344/7 = 49.142 Mhz */ + PLL2_VCO Input = HSE_VALUE/PLL2M = 1 Mhz + PLL2_VCO Output = PLL2_VCO Input * PLL2N = 344 Mhz + SAI_CLK_x = PLL2_VCO Output/PLL2P = 344/7 = 49.142 Mhz */ rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI1; rcc_ex_clk_init_struct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL2; rcc_ex_clk_init_struct.PLL2.PLL2P = 7; rcc_ex_clk_init_struct.PLL2.PLL2Q = 1; rcc_ex_clk_init_struct.PLL2.PLL2R = 1; rcc_ex_clk_init_struct.PLL2.PLL2N = 344; - if (isBoardRev2()) { - rcc_ex_clk_init_struct.PLL2.PLL2M = 25; - } else { - rcc_ex_clk_init_struct.PLL2.PLL2M = 27; - } + rcc_ex_clk_init_struct.PLL2.PLL2M = 25; + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI4A; + rcc_ex_clk_init_struct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL2; HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); - } -} -/** - * @} - */ - -/** @defgroup STM32H747I_DISCOVERY_AUDIO_OUT_Private_Functions OUT Private Functions - * @{ - */ - -/******************************************************************************* - HAL Callbacks -*******************************************************************************/ -/** - * @brief Tx Transfer completed callbacks. - * @param hsai: SAI handle - * @retval None - */ -void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) -{ - /* Manage the remaining file size and new address offset: This function - should be coded by user (its prototype is already declared in stm32h747i_discovery_audio.h) */ - BSP_AUDIO_OUT_TransferComplete_CallBack(); -} - -/** - * @brief Tx Half Transfer completed callbacks. - * @param hsai: SAI handle - * @retval None - */ -void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) -{ - /* Manage the remaining file size and new address offset: This function - should be coded by user (its prototype is already declared in stm32h747i_discovery_audio.h) */ - BSP_AUDIO_OUT_HalfTransfer_CallBack(); -} - -/** - * @brief SAI error callbacks. - * @param hsai: SAI handle - * @retval None - */ -void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai) -{ - if(hsai->Instance == AUDIO_OUT_SAIx) - { - BSP_AUDIO_OUT_Error_CallBack(); - } - else - { - BSP_AUDIO_IN_Error_CallBack(); - } -} - -/******************************************************************************* - Static Functions -*******************************************************************************/ - -/** - * @brief Initializes the Audio Codec audio interface (SAI). - * @param SaiOutMode: Audio mode to be configured for the SAI peripheral. - * @param SlotActive: Audio active slot to be configured for the SAI peripheral. - * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. - * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123 - * and user can update this configuration using - * @retval None - */ -static void SAIx_Out_Init(uint32_t SaiOutMode, uint32_t SlotActive, uint32_t AudioFreq) -{ - /* Disable SAI peripheral to allow access to SAI internal registers */ - __HAL_SAI_DISABLE(&haudio_out_sai); - - /* Configure SAI_Block_x - LSBFirst: Disabled - DataSize: 16 */ - haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE; - haudio_out_sai.Init.AudioFrequency = AudioFreq; - haudio_out_sai.Init.AudioMode = SaiOutMode; - haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; - haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL; - haudio_out_sai.Init.DataSize = SAI_DATASIZE_16; - haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; - haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; - haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS; - haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE; - haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; - haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; - haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING; - haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED; - haudio_out_sai.Init.Mckdiv = 0; - haudio_out_sai.Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE; - haudio_out_sai.Init.PdmInit.Activation = DISABLE; - haudio_out_sai.Init.PdmInit.ClockEnable = 0; - haudio_out_sai.Init.PdmInit.MicPairsNbr = 0; - - /* Configure SAI_Block_x Frame - Frame Length: 64 - Frame active Length: 32 - FS Definition: Start frame + Channel Side identification - FS Polarity: FS active Low - FS Offset: FS asserted one bit before the first bit of slot 0 */ - haudio_out_sai.FrameInit.FrameLength = 128; - haudio_out_sai.FrameInit.ActiveFrameLength = 64; - haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; - haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; - haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; - - /* Configure SAI Block_x Slot - Slot First Bit Offset: 0 - Slot Size : 16 - Slot Number: 4 - Slot Active: All slot actives */ - haudio_out_sai.SlotInit.FirstBitOffset = 0; - haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; - haudio_out_sai.SlotInit.SlotNumber = 4; - haudio_out_sai.SlotInit.SlotActive = SlotActive; - HAL_SAI_Init(&haudio_out_sai); - - /* Enable SAI peripheral to generate MCLK */ - __HAL_SAI_ENABLE(&haudio_out_sai); -} - -/** - * @brief Deinitializes the Audio Codec audio interface (SAI). - * @retval None - */ -static void SAIx_Out_DeInit(SAI_HandleTypeDef *hsai) -{ - /* Disable SAI peripheral */ - __HAL_SAI_DISABLE(hsai); - - HAL_SAI_DeInit(hsai); -} - -/** - * @} - */ - -/** @defgroup STM32H747I_DISCOVERY_AUDIO_IN_Exported_Functions IN Exported Functions - * @{ - */ - -/** - * @brief Initialize wave recording. - * @param AudioFreq: Audio frequency to be configured for the DFSDM peripheral. - * @param BitRes: Audio frequency to be configured for the DFSDM peripheral. - * @param ChnlNbr: Audio frequency to be configured for the DFSDM peripheral. - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) -{ - /* Set audio in interface to default one */ - BSP_AUDIO_IN_SelectInterface(AUDIO_IN_INTERFACE_PDM); - return BSP_AUDIO_IN_InitEx(INPUT_DEVICE_DIGITAL_MIC, AudioFreq, BitRes, ChnlNbr); -} - -/** - * @brief Initialize wave recording. - * @param InputDevice: INPUT_DEVICE_DIGITAL_MIC or INPUT_DEVICE_ANALOG_MIC. - * @param AudioFreq: Audio frequency to be configured. - * @param BitRes: Audio bit resolution to be configured.. - * @param ChnlNbr: Number of channel to be configured. - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) -{ - uint8_t ret = AUDIO_OK; - uint32_t slot_active; - - /* Store the audio record context */ - hAudioIn.Frequency = AudioFreq; - hAudioIn.BitResolution = BitRes; - hAudioIn.InputDevice = InputDevice; - hAudioIn.ChannelNbr = ChnlNbr; - - if(hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MIC) - { - if(hAudioIn.Interface == AUDIO_IN_INTERFACE_SAI) - { - /* Initialize SAI1 block B as SLAVE RX synchrounous with SAI1 block A */ - haudio_in_sai.Instance = AUDIO_IN_SAIx; - - /* Disable SAI */ - SAIx_In_DeInit(&haudio_in_sai); - - /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ - BSP_AUDIO_IN_ClockConfig(AudioFreq, NULL); /* Clock config is shared between AUDIO IN and OUT */ - - /* SAI data transfer preparation: - Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ - if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) - { - /* Init the SAI MSP: this __weak function can be redefined by the application*/ - BSP_AUDIO_IN_MspInit(); - } - - /* Configure SAI in master mode : - * - SAI1_block_B in slave RX mode synchronous from SAI1_block_A - */ - slot_active = CODEC_AUDIOFRAME_SLOT_13; - SAIx_In_Init(SAI_MODESLAVE_RX, slot_active, AudioFreq, ChnlNbr == 1); - } - else if(hAudioIn.Interface == AUDIO_IN_INTERFACE_PDM) - { - /* Initialize SAI1 block A as MASTER RX */ - haudio_in_sai.Instance = AUDIO_IN_SAI_PDMx; - - /* Disable SAI */ - SAIx_In_DeInit(&haudio_in_sai); - - /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ - BSP_AUDIO_IN_ClockConfig(AudioFreq, NULL); - - /* SAI data transfer preparation: - Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ - /* Initialize the haudio_in_sai Instance parameter */ - - if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) - { - /* Init the SAI MSP: this __weak function can be redefined by the application*/ - BSP_AUDIO_IN_MspInit(); - } - - /* Configure SAI in master mode : - * - SAI1_block_A in master RX mode - */ - slot_active = CODEC_AUDIOFRAME_SLOT_0; - SAIx_In_Init(SAI_MODEMASTER_RX, slot_active, AudioFreq, ChnlNbr == 1); - - if(BSP_AUDIO_IN_PDMToPCM_Init(AudioFreq, hAudioIn.ChannelNbr, hAudioIn.ChannelNbr) != AUDIO_OK) - { - ret = AUDIO_ERROR; - } - } - else - { - ret = AUDIO_ERROR; - } - } - else - { - /* Analog Input */ - ret = AUDIO_ERROR; - } - - /* Return AUDIO_OK when all operations are correctly done */ - return ret; -} - -/** - * @brief Initializes wave recording and playback in parallel. - * @param InputDevice: INPUT_DEVICE_DIGITAL_MICROPHONE_2 - * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, - * or OUTPUT_DEVICE_BOTH. - * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. - * @param BitRes: Audio frequency to be configured. - * @param ChnlNbr: Channel number. - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_IN_OUT_Init(uint32_t InputDevice, uint32_t OutputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr) -{ - uint32_t slot_active; - uint32_t deviceid = 0, ret = AUDIO_OK; - - /* Store the audio record context */ - hAudioIn.Frequency = AudioFreq; - hAudioIn.BitResolution = BitRes; - hAudioIn.InputDevice = InputDevice; - hAudioIn.ChannelNbr = ChnlNbr; - - /* Input device is Digital MIC2 and Codec interface is SAI */ - if (hAudioIn.InputDevice == INPUT_DEVICE_DIGITAL_MICROPHONE_2) - { - haudio_in_sai.Instance = AUDIO_IN_SAIx; - haudio_out_sai.Instance = AUDIO_OUT_SAIx; - - /* PLL clock is set depending on the AudioFreq (44.1khz vs 48khz groups) */ - BSP_AUDIO_OUT_ClockConfig(&haudio_in_sai, AudioFreq, NULL); - /* SAI data transfer preparation: - Prepare the Media to be used for the audio transfer from SAI peripheral to memory */ - if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET) - { - /* Init the SAI MSP: this __weak function can be redefined by the application*/ - BSP_AUDIO_IN_MspInit(); - } - - /* SAI data transfer preparation: - Prepare the Media to be used for the audio transfer from memory to SAI peripheral */ - if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET) - { - /* Init the SAI MSP: this __weak function can be redefined by the application*/ - BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL); - } - - /* Configure SAI in master TX mode : - * - SAI1_block_A in master TX mode - * - SAI1_block_B in slave RX mode synchronous from SAI1_block_A - */ - slot_active = CODEC_AUDIOFRAME_SLOT_13; - SAIx_In_Init(SAI_MODESLAVE_RX, slot_active, AudioFreq, ChnlNbr == 1); - - slot_active = CODEC_AUDIOFRAME_SLOT_02; - SAIx_Out_Init(SAI_MODEMASTER_TX, slot_active, AudioFreq); + sai_init(); - /* wm8994 codec initialization */ - deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS); - - if((deviceid) == WM8994_ID) - { - /* Reset the Codec Registers */ - wm8994_drv.Reset(AUDIO_I2C_ADDRESS); - /* Initialize the audio driver structure */ - audio_drv = &wm8994_drv; - ret = AUDIO_OK; - } - else - { - ret = AUDIO_ERROR; + // Sanity checks + if (frequency < 16000 || frequency > 128000) { + return 0; } - if(ret == AUDIO_OK) - { - /* Initialize the codec internal registers */ - audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice|OutputDevice, 90, AudioFreq); - } - } - else - { - ret = AUDIO_ERROR; - } - - /* Return AUDIO_OK when all operations are correctly done */ - return ret; -} - -/** - * @brief Link digital mic to specified source - * @param Interface : Audio In interface for Digital mic. It can be: - * AUDIO_IN_INTERFACE_SAI - * AUDIO_IN_INTERFACE_PDM - * @retval None - */ -void BSP_AUDIO_IN_SelectInterface(uint32_t Interface) -{ - hAudioIn.Interface = Interface; -} - -/** - * @brief Get digital mic interface - * @retval Digital mic interface. - */ -uint32_t BSP_AUDIO_IN_GetInterface(void) -{ - return (hAudioIn.Interface); -} - -/** - * @brief Return audio in channel number - * @retval Number of channel - */ -uint8_t BSP_AUDIO_IN_GetChannelNumber(void) -{ - return hAudioIn.ChannelNbr; -} - -/** - * @brief Start audio recording. - * @param pBuf: Main buffer pointer for the recorded data storing - * @param size: Current size of the recorded buffer - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_IN_Record(uint16_t *pBuf, uint32_t size) -{ - /* Start the process receive DMA */ - if(HAL_OK != HAL_SAI_Receive_DMA(&haudio_in_sai, (uint8_t*)pBuf, size)) - { - return AUDIO_ERROR; - } - - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; -} - -/** - * @brief Stop audio recording. - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_IN_Stop(void) -{ - /* Call the Media layer stop function */ - HAL_SAI_DMAStop(&haudio_in_sai); - - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; -} - -/** - * @brief Pause the audio file stream. - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_IN_Pause(void) -{ - if (hAudioIn.InputDevice == INPUT_DEVICE_ANALOG_MIC) - { - return AUDIO_ERROR; - } - else - { - /* Call the Media layer pause function */ - HAL_SAI_DMAPause(&haudio_in_sai); - } - - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; -} - -/** - * @brief Resume the audio file stream. - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_IN_Resume(void) -{ - if (hAudioIn.InputDevice == INPUT_DEVICE_ANALOG_MIC) - { - return AUDIO_ERROR; - } - else - { - /* Call the Media layer resume function */ - HAL_SAI_DMAResume(&haudio_in_sai); - } - - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; -} - -/** - * @brief Controls the audio in volume level. - * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for - * Mute and 100 for Max volume level). - * @retval AUDIO_OK if correct communication, else wrong communication - */ -uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume) -{ - /* Set the Global variable AudioInVolume */ - AudioInVolume = Volume; - - /* Return AUDIO_OK when all operations are correctly done */ - return AUDIO_OK; -} - -/** - * @brief Deinit the audio IN peripherals. - * @retval None - */ -void BSP_AUDIO_IN_DeInit(void) -{ - SAIx_In_DeInit(&haudio_in_sai); - - BSP_AUDIO_IN_MspDeInit(); -} - -/** -* @brief Initialize the PDM library. -* @param AudioFreq: Audio sampling frequency -* @param ChnlNbrIn: Number of input audio channels in the PDM buffer -* @param ChnlNbrOut: Number of desired output audio channels in the resulting PCM buffer -* @retval None -*/ -uint8_t BSP_AUDIO_IN_PDMToPCM_Init(uint32_t AudioFreq, uint32_t ChnlNbrIn, uint32_t ChnlNbrOut) -{ - uint32_t index = 0; - - /* Enable CRC peripheral to unlock the PDM library */ - __HAL_RCC_CRC_CLK_ENABLE(); - - for(index = 0; index < ChnlNbrIn; index++) - { - /* Init PDM filters */ - PDM_FilterHandler[index].bit_order = PDM_FILTER_BIT_ORDER_MSB; - PDM_FilterHandler[index].endianness = PDM_FILTER_ENDIANNESS_LE; - PDM_FilterHandler[index].high_pass_tap = 2122358088; - PDM_FilterHandler[index].out_ptr_channels = ChnlNbrOut; - PDM_FilterHandler[index].in_ptr_channels = ChnlNbrIn; - PDM_Filter_Init((PDM_Filter_Handler_t *)(&PDM_FilterHandler[index])); - - /* PDM lib config phase */ - PDM_FilterConfig[index].output_samples_number = AudioFreq/1000; - PDM_FilterConfig[index].mic_gain = 24; - PDM_FilterConfig[index].decimation_factor = PDM_FILTER_DEC_FACTOR_64; - PDM_Filter_setConfig((PDM_Filter_Handler_t *)&PDM_FilterHandler[index], &PDM_FilterConfig[index]); - } - - return AUDIO_OK; -} - - -/** -* @brief Converts audio format from PDM to PCM. - -* @param PDMBuf: Pointer to PDM buffer data -* @param PCMBuf: Pointer to PCM buffer data -* @retval AUDIO_OK in case of success, AUDIO_ERROR otherwise -*/ -uint8_t BSP_AUDIO_IN_PDMToPCM(uint16_t *PDMBuf, uint16_t *PCMBuf) -{ - uint32_t index = 0; - - for(index = 0; index < hAudioIn.ChannelNbr; index++) - { - PDM_Filter(&((uint8_t*)(PDMBuf))[index], (uint16_t*)&(PCMBuf[index]), &PDM_FilterHandler[index]); - } - - return AUDIO_OK; -} - -/** - * @brief User callback when record buffer is filled. - * @retval None - */ -__weak void BSP_AUDIO_IN_TransferComplete_CallBack(void) -{ - /* This function should be implemented by the user application. - It is called into this driver when the current buffer is filled - to prepare the next buffer pointer and its size. */ -} - -/** - * @brief Manages the DMA Half Transfer complete event. - * @retval None - */ -__weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void) -{ - /* This function should be implemented by the user application. - It is called into this driver when the current buffer is filled - to prepare the next buffer pointer and its size. */ -} - -/** - * @brief User callback when record buffer is filled. - * @param InputDevice: INPUT_DEVICE_DIGITAL_MIC1 or INPUT_DEVICE_DIGITAL_MIC2 - */ -__weak void BSP_AUDIO_IN_TransferComplete_CallBackEx(uint32_t InputDevice) -{ - /* This function should be implemented by the user application. - It is called into this driver when the current buffer is filled - to prepare the next buffer pointer and its size. */ -} - -/** - * @brief User callback when record buffer is filled. - * @param InputDevice: INPUT_DEVICE_DIGITAL_MIC1 or INPUT_DEVICE_DIGITAL_MIC2 - */ -__weak void BSP_AUDIO_IN_HalfTransfer_CallBackEx(uint32_t InputDevice) -{ - /* This function should be implemented by the user application. - It is called into this driver when the current buffer is filled - to prepare the next buffer pointer and its size. */ -} - -/** - * @brief Audio IN Error callback function. - * @retval None - */ -__weak void BSP_AUDIO_IN_Error_CallBack(void) -{ - /* This function is called when an Interrupt due to transfer error on or peripheral - error occurs. */ -} - -/** - * @brief Initialize BSP_AUDIO_IN MSP. - * @retval None - */ -__weak void BSP_AUDIO_IN_MspInit(void) -{ - SAIx_In_MspInit(&haudio_in_sai, NULL); -} - -/** - * @brief DeInitialize BSP_AUDIO_IN MSP. - * @retval None - */ -__weak void BSP_AUDIO_IN_MspDeInit(void) -{ - SAIx_In_MspDeInit(&haudio_in_sai, NULL); -} - -/** - * @brief Clock Config. - * @param AudioFreq: Audio frequency used to play the audio stream. - * @param Params: pointer on additional configuration parameters, can be NULL. - * @note This API is called by BSP_AUDIO_IN_Init() - * Being __weak it can be overwritten by the application - * @retval None - */ -__weak void BSP_AUDIO_IN_ClockConfig(uint32_t AudioFreq, void *Params) -{ - RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; - - HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); - - /* Set the PLL configuration according to the audio frequency */ - if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K)) - { - /* SAI clock config: - PLL2_VCO Input = HSE_VALUE/PLL2M = 1 Mhz - PLL2_VCO Output = PLL2_VCO Input * PLL2N = 429 Mhz - SAI_CLK_x = PLL2_VCO Output/PLL2P = 429/38 = 11.289 Mhz */ - rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI1; - rcc_ex_clk_init_struct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL2; - rcc_ex_clk_init_struct.PLL2.PLL2P = 38; - rcc_ex_clk_init_struct.PLL2.PLL2Q = 1; - rcc_ex_clk_init_struct.PLL2.PLL2R = 1; - rcc_ex_clk_init_struct.PLL2.PLL2N = 429; - if (isBoardRev2()) { - rcc_ex_clk_init_struct.PLL2.PLL2M = 25; - } else { - rcc_ex_clk_init_struct.PLL2.PLL2M = 27; + if (g_channels != 1 && g_channels != 2) { + return 0; } - if (hAudioIn.Interface == AUDIO_IN_INTERFACE_PDM) - { - rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI4A; - rcc_ex_clk_init_struct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL2; - } - HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); - } - else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_32K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */ - { - /* SAI clock config: - PLL2_VCO Input = HSE_VALUE/PLL2M = 1 Mhz - PLL2_VCO Output = PLL2_VCO Input * PLL2N = 344 Mhz - SAI_CLK_x = PLL2_VCO Output/PLL2P = 344/7 = 49.142 Mhz */ - rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI1; - rcc_ex_clk_init_struct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL2; - rcc_ex_clk_init_struct.PLL2.PLL2P = 7; - rcc_ex_clk_init_struct.PLL2.PLL2Q = 1; - rcc_ex_clk_init_struct.PLL2.PLL2R = 1; - rcc_ex_clk_init_struct.PLL2.PLL2N = 344; - if (isBoardRev2()) { - rcc_ex_clk_init_struct.PLL2.PLL2M = 25; - } else { - rcc_ex_clk_init_struct.PLL2.PLL2M = 27; + uint32_t decimation_factor = AUDIO_SAI_FREQKHZ / (frequency / 1000); + uint32_t decimation_factor_const = get_decimation_factor(decimation_factor); + if (decimation_factor_const == 0) { + return 0; } - if (hAudioIn.Interface == AUDIO_IN_INTERFACE_PDM) - { - rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI4A; - rcc_ex_clk_init_struct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL2; + uint32_t samples_per_channel = (PDM_BUFFER_SIZE * 8) / (decimation_factor * g_channels * 2); // Half a transfer + + hsai.Instance = AUDIO_SAI; + hsai.Init.Protocol = SAI_FREE_PROTOCOL; + hsai.Init.AudioMode = SAI_MODEMASTER_RX; + hsai.Init.DataSize = (g_channels == 1) ? SAI_DATASIZE_8 : SAI_DATASIZE_16; + hsai.Init.FirstBit = SAI_FIRSTBIT_LSB; + hsai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; + hsai.Init.Synchro = SAI_ASYNCHRONOUS; + hsai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; + hsai.Init.NoDivider = SAI_MASTERDIVIDER_DISABLE; + hsai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; + hsai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; + hsai.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV; + hsai.Init.MonoStereoMode = (g_channels == 1) ? SAI_MONOMODE: SAI_STEREOMODE; + hsai.Init.CompandingMode = SAI_NOCOMPANDING; + hsai.Init.TriState = SAI_OUTPUT_RELEASED; + + // The master clock output (MCLK_x) is disabled and the SAI clock + // is passed out to SCK_x bit clock. SCKx frequency = SAI_KER_CK / MCKDIV / 2 + hsai.Init.Mckdiv = AUDIO_SAI_MCKDIV; //2.048MHz + hsai.Init.MckOutput = SAI_MCK_OUTPUT_DISABLE; + hsai.Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE; + + // Enable and configure PDM mode. + hsai.Init.PdmInit.Activation = ENABLE; + hsai.Init.PdmInit.MicPairsNbr = 1; + hsai.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK1_ENABLE; + + hsai.FrameInit.FrameLength = 16; + hsai.FrameInit.ActiveFrameLength = 1; + hsai.FrameInit.FSDefinition = SAI_FS_STARTFRAME; + hsai.FrameInit.FSPolarity = SAI_FS_ACTIVE_HIGH; + hsai.FrameInit.FSOffset = SAI_FS_FIRSTBIT; + + hsai.SlotInit.FirstBitOffset = 0; + hsai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; + hsai.SlotInit.SlotNumber = (g_channels == 1) ? 2 : 1; + hsai.SlotInit.SlotActive = (g_channels == 1) ? (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1) : SAI_SLOTACTIVE_0; + + // Initialize the SAI + HAL_SAI_DeInit(&hsai); + if (HAL_SAI_Init(&hsai) != HAL_OK) { + return 0; } - HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); - } -} -/** - * @} - */ - - -/** @defgroup STM32H747I_DISCOVERY_AUDIO_IN_Private_Functions IN Private Functions - * @{ - */ - -/******************************************************************************* - HAL Callbacks -*******************************************************************************/ - -/** - * @brief Half reception complete callback. - * @param hsai: SAI handle. - * @retval None - */ -void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai) -{ - /* Manage the remaining file size and new address offset: This function should be coded by user */ - BSP_AUDIO_IN_HalfTransfer_CallBack(); -} - -/** - * @brief Reception complete callback. - * @param hsai: SAI handle. - * @retval None - */ -void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai) -{ - /* Call the record update function to get the next buffer to fill and its size (size is ignored) */ - BSP_AUDIO_IN_TransferComplete_CallBack(); -} - -/******************************************************************************* - Static Functions -*******************************************************************************/ -/** - * @brief Initializes SAI Audio IN MSP. - * @param hsai: SAI handle - * @param Params: pointer on additional configuration parameters, can be NULL. - * @retval None - */ -static void SAIx_In_MspInit(SAI_HandleTypeDef *hsai, void *Params) -{ - static DMA_HandleTypeDef hdma_sai_rx; - GPIO_InitTypeDef gpio_init_structure; - - if(hsai->Instance == AUDIO_IN_SAI_PDMx) - { - /* Enable SAI clock */ - AUDIO_IN_SAI_PDMx_CLK_ENABLE(); - - AUDIO_IN_SAI_PDMx_CLK_IN_ENABLE(); - AUDIO_IN_SAI_PDMx_DATA_IN_ENABLE(); - - gpio_init_structure.Pin = AUDIO_IN_SAI_PDMx_CLK_IN_PIN; - gpio_init_structure.Mode = GPIO_MODE_AF_PP; - gpio_init_structure.Pull = GPIO_NOPULL; - gpio_init_structure.Speed = GPIO_SPEED_FREQ_MEDIUM; - gpio_init_structure.Alternate = AUDIO_IN_SAI_PDMx_DATA_CLK_AF; - HAL_GPIO_Init(AUDIO_IN_SAI_PDMx_CLK_IN_PORT, &gpio_init_structure); - - gpio_init_structure.Pull = GPIO_PULLUP; - gpio_init_structure.Speed = GPIO_SPEED_FREQ_MEDIUM; - gpio_init_structure.Pin = AUDIO_IN_SAI_PDMx_DATA_IN_PIN; - HAL_GPIO_Init(AUDIO_IN_SAI_PDMx_DATA_IN_PORT, &gpio_init_structure); - - AUDIO_IN_SAI_PDMx_FS_SCK_ENABLE(); - - /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ - gpio_init_structure.Pin = AUDIO_IN_SAI_PDMx_FS_PIN | AUDIO_IN_SAI_PDMx_SCK_PIN; - gpio_init_structure.Mode = GPIO_MODE_AF_PP; - gpio_init_structure.Pull = GPIO_NOPULL; - gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; - gpio_init_structure.Alternate = AUDIO_IN_SAI_PDMx_FS_SCK_AF; - HAL_GPIO_Init(AUDIO_IN_SAI_PDMx_FS_SCK_GPIO_PORT, &gpio_init_structure); - - /* Enable the DMA clock */ - AUDIO_IN_SAI_PDMx_DMAx_CLK_ENABLE(); - - /* Configure the hdma_sai_rx handle parameters */ - hdma_sai_rx.Init.Request = AUDIO_IN_SAI_PDMx_DMAx_REQUEST; - hdma_sai_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; - hdma_sai_rx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_sai_rx.Init.MemInc = DMA_MINC_ENABLE; - hdma_sai_rx.Init.PeriphDataAlignment = AUDIO_IN_SAI_PDMx_DMAx_PERIPH_DATA_SIZE; - hdma_sai_rx.Init.MemDataAlignment = AUDIO_IN_SAI_PDMx_DMAx_MEM_DATA_SIZE; - hdma_sai_rx.Init.Mode = DMA_CIRCULAR; - hdma_sai_rx.Init.Priority = DMA_PRIORITY_HIGH; - hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; - hdma_sai_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; - hdma_sai_rx.Init.MemBurst = DMA_MBURST_SINGLE; - hdma_sai_rx.Init.PeriphBurst = DMA_MBURST_SINGLE; - - hdma_sai_rx.Instance = AUDIO_IN_SAI_PDMx_DMAx_STREAM; - - /* Associate the DMA handle */ - __HAL_LINKDMA(hsai, hdmarx, hdma_sai_rx); - - /* Deinitialize the Stream for new transfer */ - HAL_DMA_DeInit(&hdma_sai_rx); - - /* Configure the DMA Stream */ - HAL_DMA_Init(&hdma_sai_rx); - - /* SAI DMA IRQ Channel configuration */ - HAL_NVIC_SetPriority(AUDIO_IN_SAI_PDMx_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); - HAL_NVIC_EnableIRQ(AUDIO_IN_SAI_PDMx_DMAx_IRQ); - } - else - { - /* Enable SAI clock */ - AUDIO_IN_SAIx_CLK_ENABLE(); - - /* Enable SD GPIO clock */ - AUDIO_IN_SAIx_SD_ENABLE(); - /* CODEC_SAI pin configuration: SD pin */ - gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; - gpio_init_structure.Mode = GPIO_MODE_AF_PP; - gpio_init_structure.Pull = GPIO_NOPULL; - gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; - gpio_init_structure.Alternate = AUDIO_IN_SAIx_AF; - HAL_GPIO_Init(AUDIO_IN_SAIx_SD_GPIO_PORT, &gpio_init_structure); - - /* Enable Audio INT GPIO clock */ - AUDIO_IN_INT_GPIO_ENABLE(); - /* Audio INT pin configuration: input */ - gpio_init_structure.Pin = AUDIO_IN_INT_GPIO_PIN; - gpio_init_structure.Mode = GPIO_MODE_INPUT; - gpio_init_structure.Pull = GPIO_NOPULL; - gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; - HAL_GPIO_Init(AUDIO_IN_INT_GPIO_PORT, &gpio_init_structure); - /* Enable the DMA clock */ - AUDIO_IN_SAIx_DMAx_CLK_ENABLE(); + // Enable the DMA clock + AUDIO_SAI_DMA_CLK_ENABLE(); - /* Configure the hdma_sai_rx handle parameters */ - hdma_sai_rx.Init.Request = AUDIO_IN_SAIx_DMAx_REQUEST; + // Configure the SAI DMA + hdma_sai_rx.Instance = AUDIO_SAI_DMA_STREAM; + hdma_sai_rx.Init.Request = AUDIO_SAI_DMA_REQUEST; hdma_sai_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_sai_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_sai_rx.Init.MemInc = DMA_MINC_ENABLE; - hdma_sai_rx.Init.PeriphDataAlignment = AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE; - hdma_sai_rx.Init.MemDataAlignment = AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE; + hdma_sai_rx.Init.PeriphDataAlignment = (g_channels == 1) ? DMA_PDATAALIGN_BYTE : DMA_PDATAALIGN_HALFWORD; + hdma_sai_rx.Init.MemDataAlignment = (g_channels == 1) ? DMA_MDATAALIGN_BYTE : DMA_MDATAALIGN_HALFWORD; hdma_sai_rx.Init.Mode = DMA_CIRCULAR; hdma_sai_rx.Init.Priority = DMA_PRIORITY_HIGH; - hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; hdma_sai_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma_sai_rx.Init.MemBurst = DMA_MBURST_SINGLE; hdma_sai_rx.Init.PeriphBurst = DMA_MBURST_SINGLE; + __HAL_LINKDMA(&hsai, hdmarx, hdma_sai_rx); - hdma_sai_rx.Instance = AUDIO_IN_SAIx_DMAx_STREAM; - - /* Associate the DMA handle */ - __HAL_LINKDMA(hsai, hdmarx, hdma_sai_rx); - - /* Deinitialize the Stream for new transfer */ + // Initialize the DMA stream HAL_DMA_DeInit(&hdma_sai_rx); + if (HAL_DMA_Init(&hdma_sai_rx) != HAL_OK) { + return 0; + } - /* Configure the DMA Stream */ - HAL_DMA_Init(&hdma_sai_rx); + // Configure and enable SAI DMA IRQ Channel + HAL_NVIC_SetPriority(AUDIO_SAI_DMA_IRQ, AUDIO_IN_IRQ_PREPRIO, 0); + HAL_NVIC_EnableIRQ(AUDIO_SAI_DMA_IRQ); + + // Init CRC for the PDM library + hcrc.Instance = CRC; + hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE; + hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE; + hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE; + hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE; + hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES; + if (HAL_CRC_Init(&hcrc) != HAL_OK) { + return 0; + } + __HAL_CRC_DR_RESET(&hcrc); + + // Configure PDM filters + for (int i=0; iInstance == AUDIO_IN_SAI_PDMx) - { - /* Deinitialize the DMA stream */ - HAL_DMA_Abort(hsai->hdmarx); - - HAL_SAI_DeInit(hsai); - /* Disable SAI peripheral */ - __HAL_SAI_DISABLE(hsai); - - /* Deinitialize the DMA stream */ - HAL_DMA_DeInit(hsai->hdmarx); - - gpio_init_structure.Pin = AUDIO_IN_SAI_PDMx_CLK_IN_PIN; - HAL_GPIO_DeInit(AUDIO_IN_SAI_PDMx_CLK_IN_PORT, gpio_init_structure.Pin); - - gpio_init_structure.Pin = AUDIO_IN_SAI_PDMx_DATA_IN_PIN; - HAL_GPIO_DeInit(AUDIO_IN_SAI_PDMx_DATA_IN_PORT, gpio_init_structure.Pin); - - /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/ - gpio_init_structure.Pin = AUDIO_IN_SAI_PDMx_FS_PIN | AUDIO_IN_SAI_PDMx_SCK_PIN; - HAL_GPIO_DeInit(AUDIO_IN_SAI_PDMx_FS_SCK_GPIO_PORT, gpio_init_structure.Pin); - - /* Disable SAI clock */ - AUDIO_IN_SAI_PDMx_CLK_DISABLE(); - } - else - { - /* SAI DMA IRQ Channel deactivation */ - HAL_NVIC_DisableIRQ(AUDIO_IN_SAIx_DMAx_IRQ); - - if(hsai->Instance == AUDIO_IN_SAIx) - { - /* Deinitialize the DMA stream */ - HAL_DMA_DeInit(hsai->hdmatx); + // Stop SAI DMA. + if (hdma_sai_rx.Instance != NULL) { + HAL_SAI_DMAStop(&hsai); } - /* Disable SAI peripheral */ - __HAL_SAI_DISABLE(hsai); + // Disable IRQs + HAL_NVIC_DisableIRQ(AUDIO_SAI_DMA_IRQ); - /* Deactivates CODEC_SAI pin SD by putting them in input mode */ - gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN; - HAL_GPIO_DeInit(AUDIO_IN_SAIx_SD_GPIO_PORT, gpio_init_structure.Pin); + if (hsai.Instance != NULL) { + HAL_SAI_DeInit(&hsai); + hsai.Instance = NULL; + } - gpio_init_structure.Pin = AUDIO_IN_INT_GPIO_PIN; - HAL_GPIO_DeInit(AUDIO_IN_INT_GPIO_PORT, gpio_init_structure.Pin); + if (hdma_sai_rx.Instance != NULL) { + HAL_DMA_DeInit(&hdma_sai_rx); + hdma_sai_rx.Instance = NULL; + } - /* Disable SAI clock */ - AUDIO_IN_SAIx_CLK_DISABLE(); - } + g_channels = 0; + //free(g_pcmbuf); + g_pcmbuf = NULL; } -/** - * @brief Initializes the Audio Codec audio interface (SAI). - * @param SaiInMode: Audio mode to be configured for the SAI peripheral. - * @param SlotActive: Audio active slot to be configured for the SAI peripheral. - * @param AudioFreq: Audio frequency to be configured for the SAI peripheral. - * @retval None - */ -static void SAIx_In_Init(uint32_t SaiInMode, uint32_t SlotActive, uint32_t AudioFreq, bool mono) +void audio_pendsv_callback(void) { - /* Disable SAI peripheral to allow access to SAI internal registers */ - __HAL_SAI_DISABLE(&haudio_in_sai); - - /* Configure SAI_Block_x - LSBFirst: Disabled - DataSize: 16 */ - haudio_in_sai.Init.MonoStereoMode = mono ? SAI_MONOMODE : SAI_STEREOMODE; - haudio_in_sai.Init.AudioFrequency = AudioFreq; - haudio_in_sai.Init.AudioMode = SaiInMode; - haudio_in_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; - haudio_in_sai.Init.Protocol = SAI_FREE_PROTOCOL; - haudio_in_sai.Init.DataSize = SAI_DATASIZE_16; - haudio_in_sai.Init.FirstBit = SAI_FIRSTBIT_MSB; - haudio_in_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; - haudio_in_sai.Init.Synchro = SAI_SYNCHRONOUS; - haudio_in_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; - haudio_in_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; - haudio_in_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; - haudio_in_sai.Init.CompandingMode = SAI_NOCOMPANDING; - haudio_in_sai.Init.TriState = SAI_OUTPUT_RELEASED; - haudio_in_sai.Init.Mckdiv = 0; - haudio_in_sai.Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE; - haudio_in_sai.Init.PdmInit.Activation = DISABLE; - - /* Configure SAI_Block_x Frame - Frame Length: 64 - Frame active Length: 32 - FS Definition: Start frame + Channel Side identification - FS Polarity: FS active Low - FS Offset: FS asserted one bit before the first bit of slot 0 */ - haudio_in_sai.FrameInit.FrameLength = 128; - haudio_in_sai.FrameInit.ActiveFrameLength = 64; - haudio_in_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; - haudio_in_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; - haudio_in_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; - - /* Configure SAI Block_x Slot - Slot First Bit Offset: 0 - Slot Size : 16 - Slot Number: 4 - Slot Active: All slot active */ - haudio_in_sai.SlotInit.FirstBitOffset = 0; - haudio_in_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; - haudio_in_sai.SlotInit.SlotNumber = 4; - haudio_in_sai.SlotInit.SlotActive = SlotActive; - - if(hAudioIn.Interface == AUDIO_IN_INTERFACE_PDM) - { - haudio_in_sai.Init.AudioFrequency = AudioFreq * 8; - haudio_in_sai.Init.Synchro = SAI_ASYNCHRONOUS; - haudio_in_sai.Init.NoDivider = SAI_MASTERDIVIDER_DISABLE; + // Check for half transfer complete. + if ((xfer_status & DMA_XFER_HALF)) { + // Clear buffer state. + xfer_status &= ~(DMA_XFER_HALF); - haudio_in_sai.Init.PdmInit.Activation = ENABLE; - haudio_in_sai.Init.PdmInit.MicPairsNbr = 1; - haudio_in_sai.Init.PdmInit.ClockEnable = SAI_PDM_CLOCK1_ENABLE; - haudio_in_sai.Init.FirstBit = SAI_FIRSTBIT_LSB; - haudio_in_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE; + // Convert PDM samples to PCM. + for (int i=0; i
© Copyright (c) 2019 STMicroelectronics. - * All rights reserved.
- * - * This software component is licensed by ST under BSD 3-Clause license, - * the "License"; You may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * opensource.org/licenses/BSD-3-Clause - * - ****************************************************************************** - */ +#ifdef TARGET_STM -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32H747I_DISCOVERY_AUDIO_H -#define __STM32H747I_DISCOVERY_AUDIO_H +#include "stdbool.h" -#ifdef __cplusplus - extern "C" { -#endif +// SAI4 +#define AUDIO_SAI (SAI4_Block_A) +// SCKx frequency = SAI_KER_CK / MCKDIV / 2 +#define AUDIO_SAI_MCKDIV (12) +#define AUDIO_SAI_FREQKHZ (2048U) // 2048KHz +#define AUDIO_SAI_NBR_CHANNELS (2) // Default number of channels. -/* Includes ------------------------------------------------------------------*/ -/* Include audio component Driver */ -#include "wm8994.h" -#include "stm32h7xx_hal.h" -#include -#include -/* Include PDM to PCM lib header file */ -#include "pdm2pcm_glo.h" +#define AUDIO_SAI_CK_PORT (GPIOE) +#define AUDIO_SAI_CK_PIN (GPIO_PIN_2) +#define AUDIO_SAI_CK_AF (GPIO_AF10_SAI4) -/** @addtogroup BSP - * @{ - */ +#define AUDIO_SAI_D1_PORT (GPIOB) +#define AUDIO_SAI_D1_PIN (GPIO_PIN_2) +#define AUDIO_SAI_D1_AF (GPIO_AF10_SAI4) -/** @addtogroup STM32H747I_DISCOVERY - * @{ - */ - -/** @addtogroup STM32H747I_DISCOVERY_AUDIO - * @{ - */ +#define AUDIO_SAI_DMA_STREAM BDMA_Channel1 +#define AUDIO_SAI_DMA_REQUEST BDMA_REQUEST_SAI4_A +#define AUDIO_SAI_DMA_IRQ BDMA_Channel1_IRQn +#define AUDIO_SAI_DMA_IRQHandler BDMA_Channel1_IRQHandler -/** @defgroup STM32H747I_DISCOVERY_AUDIO_Exported_Types Exported Types - * @{ - */ -typedef struct -{ - uint32_t Frequency; /* Record Frequency */ - uint32_t BitResolution; /* Record bit resolution */ - uint32_t ChannelNbr; /* Record Channel Number */ - uint16_t *pRecBuf; /* Pointer to record user buffer */ - uint32_t RecSize; /* Size to record in mono, double size to record in stereo */ - uint32_t InputDevice; /* Audio Input Device */ - uint32_t Interface; /* Audio Input Interface */ - uint32_t MultiBuffMode; /* Multi buffer mode selection */ -}AUDIOIN_ContextTypeDef; -/** - * @} - */ +#define AUDIO_SAI_CLK_ENABLE() __HAL_RCC_SAI4_CLK_ENABLE() +#define AUDIO_SAI_CLK_DISABLE() __HAL_RCC_SAI4_CLK_DISABLE() +#define AUDIO_SAI_DMA_CLK_ENABLE() __HAL_RCC_BDMA_CLK_ENABLE() -/** @defgroup STM32H747I_DISCOVERY_AUDIO_Exported_Constants Exported Constants - * @{ - */ -#define BSP_AUDIO_FREQUENCY_96K SAI_AUDIO_FREQUENCY_96K -#define BSP_AUDIO_FREQUENCY_48K SAI_AUDIO_FREQUENCY_48K -#define BSP_AUDIO_FREQUENCY_44K SAI_AUDIO_FREQUENCY_44K -#define BSP_AUDIO_FREQUENCY_32K SAI_AUDIO_FREQUENCY_32K -#define BSP_AUDIO_FREQUENCY_22K SAI_AUDIO_FREQUENCY_22K -#define BSP_AUDIO_FREQUENCY_16K SAI_AUDIO_FREQUENCY_16K -#define BSP_AUDIO_FREQUENCY_11K SAI_AUDIO_FREQUENCY_11K -#define BSP_AUDIO_FREQUENCY_8K SAI_AUDIO_FREQUENCY_8K - -/*------------------------------------------------------------------------------ - USER SAI defines parameters - -----------------------------------------------------------------------------*/ -/** In W8994 codec the Audio frame contains 4 slots : TDM Mode - * TDM format : - * +------------------|------------------|--------------------|-------------------+ - * | CODEC_SLOT0 Left | CODEC_SLOT1 Left | CODEC_SLOT0 Right | CODEC_SLOT1 Right | - * +------------------------------------------------------------------------------+ - */ -/* To have 2 separate audio stream in Both headphone and speaker the 4 slot must be activated */ -#define CODEC_AUDIOFRAME_SLOT_0123 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3 - -/* To have an audio stream in headphone only SAI Slot 0 and Slot 2 must be activated */ -#define CODEC_AUDIOFRAME_SLOT_02 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_2 -/* To have an audio stream in speaker only SAI Slot 1 and Slot 3 must be activated */ -#define CODEC_AUDIOFRAME_SLOT_13 SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_3 -/* To have an audio stream in SAI PDM input Slot 0 must be activated */ -#define CODEC_AUDIOFRAME_SLOT_0 SAI_SLOTACTIVE_0 - -/*------------------------------------------------------------------------------ - AUDIO OUT CONFIGURATION -------------------------------------------------------------------------------*/ -/* SAI peripheral configuration defines */ -#define AUDIO_OUT_SAIx SAI1_Block_A -#define AUDIO_OUT_SAIx_CLK_ENABLE() __HAL_RCC_SAI1_CLK_ENABLE() -#define AUDIO_OUT_SAIx_CLK_DISABLE() __HAL_RCC_SAI1_CLK_DISABLE() -#define AUDIO_OUT_SAIx_AF GPIO_AF6_SAI1 - -#define AUDIO_OUT_SAIx_MCLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE() -#define AUDIO_OUT_SAIx_MCLK_GPIO_PORT GPIOG -#define AUDIO_OUT_SAIx_MCLK_PIN GPIO_PIN_7 -#define AUDIO_OUT_SAIx_SD_FS_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() -#define AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT GPIOE -#define AUDIO_OUT_SAIx_FS_PIN GPIO_PIN_4 -#define AUDIO_OUT_SAIx_SCK_PIN GPIO_PIN_5 -#define AUDIO_OUT_SAIx_SD_PIN GPIO_PIN_6 - -/* SAI DMA Stream definitions */ -#define AUDIO_OUT_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() -#define AUDIO_OUT_SAIx_DMAx_STREAM DMA2_Stream1 -#define AUDIO_OUT_SAIx_DMAx_REQUEST DMA_REQUEST_SAI1_A -#define AUDIO_OUT_SAIx_DMAx_IRQ DMA2_Stream1_IRQn -#define AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD -#define AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD -#define AUDIO_OUT_SAIx_DMAx_IRQHandler DMA2_Stream1_IRQHandler - -/* Select the interrupt preemption priority and subpriority for the DMA interrupt */ -#define AUDIO_OUT_IRQ_PREPRIO ((uint32_t)0x0E) - -/*------------------------------------------------------------------------------ - AUDIO IN CONFIGURATION -------------------------------------------------------------------------------*/ -/* SAI peripheral configuration defines */ -#define AUDIO_IN_SAIx SAI1_Block_B -#define AUDIO_IN_SAIx_CLK_ENABLE() __HAL_RCC_SAI1_CLK_ENABLE() -#define AUDIO_IN_SAIx_CLK_DISABLE() __HAL_RCC_SAI1_CLK_DISABLE() -#define AUDIO_IN_SAIx_AF GPIO_AF6_SAI1 -#define AUDIO_IN_SAIx_SD_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() -#define AUDIO_IN_SAIx_SD_GPIO_PORT GPIOE -#define AUDIO_IN_SAIx_SD_PIN GPIO_PIN_3 - -/* SAI DMA Stream definitions */ -#define AUDIO_IN_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() -#define AUDIO_IN_SAIx_DMAx_STREAM DMA2_Stream4 -#define AUDIO_IN_SAIx_DMAx_REQUEST DMA_REQUEST_SAI1_B -#define AUDIO_IN_SAIx_DMAx_IRQ DMA2_Stream4_IRQn -#define AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD -#define AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD - -#define AUDIO_IN_SAIx_DMAx_IRQHandler DMA2_Stream4_IRQHandler - -#define AUDIO_IN_INT_GPIO_ENABLE() __HAL_RCC_GPIOJ_CLK_ENABLE() -#define AUDIO_IN_INT_GPIO_PORT GPIOJ -#define AUDIO_IN_INT_GPIO_PIN GPIO_PIN_15 -#define AUDIO_IN_INT_IRQ EXTI15_10_IRQn - -/* SAI PDM input definitions */ -#define AUDIO_IN_SAI_PDMx SAI4_Block_A -#define AUDIO_IN_SAI_PDMx_CLK_ENABLE() __HAL_RCC_SAI4_CLK_ENABLE() -#define AUDIO_IN_SAI_PDMx_CLK_DISABLE() __HAL_RCC_SAI4_CLK_DISABLE() -#define AUDIO_IN_SAI_PDMx_FS_SCK_AF GPIO_AF8_SAI4 -#define AUDIO_IN_SAI_PDMx_FS_SCK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() -#define AUDIO_IN_SAI_PDMx_FS_SCK_GPIO_PORT GPIOE -#define AUDIO_IN_SAI_PDMx_FS_PIN GPIO_PIN_4 -#define AUDIO_IN_SAI_PDMx_SCK_PIN GPIO_PIN_5 - -#define AUDIO_IN_SAI_PDMx_CLK_IN_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() -#define AUDIO_IN_SAI_PDMx_CLK_IN_PIN GPIO_PIN_2 -#define AUDIO_IN_SAI_PDMx_CLK_IN_PORT GPIOE -#define AUDIO_IN_SAI_PDMx_DATA_IN_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() -#define AUDIO_IN_SAI_PDMx_DATA_IN_PIN GPIO_PIN_2 -#define AUDIO_IN_SAI_PDMx_DATA_IN_PORT GPIOB -#define AUDIO_IN_SAI_PDMx_DATA_CLK_AF GPIO_AF10_SAI4 -#define AUDIO_IN_SAI_PDMx_IRQHandler SAI4_IRQHandler -#define AUDIO_IN_SAI_PDMx_IRQ SAI4_IRQn - -/* SAI PDM DMA Stream definitions */ -#define AUDIO_IN_SAI_PDMx_DMAx_CLK_ENABLE() __HAL_RCC_BDMA_CLK_ENABLE() -#define AUDIO_IN_SAI_PDMx_DMAx_STREAM BDMA_Channel1 -#define AUDIO_IN_SAI_PDMx_DMAx_REQUEST BDMA_REQUEST_SAI4_A -#define AUDIO_IN_SAI_PDMx_DMAx_IRQ BDMA_Channel1_IRQn -#define AUDIO_IN_SAI_PDMx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD -#define AUDIO_IN_SAI_PDMx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD -#define AUDIO_IN_SAI_PDMx_DMAx_IRQHandler BDMA_Channel1_IRQHandler - -/* Select the interrupt preemption priority and subpriority for the DMA interrupt */ #define AUDIO_IN_IRQ_PREPRIO ((uint32_t)0x0F) -#define AUDIO_I2C_ADDRESS (0x2c) - -/*------------------------------------------------------------------------------ - CONFIGURATION: Audio Driver Configuration parameters -------------------------------------------------------------------------------*/ - -#define AUDIODATA_SIZE ((uint32_t)2) /* 16-bits audio data size */ - -/* Audio status definition */ -#define AUDIO_OK ((uint8_t)0) -#define AUDIO_ERROR ((uint8_t)1) -#define AUDIO_TIMEOUT ((uint8_t)2) - -/* Audio In default settings */ -#define DEFAULT_AUDIO_IN_FREQ BSP_AUDIO_FREQUENCY_16K -#define DEFAULT_AUDIO_IN_BIT_RESOLUTION ((uint8_t)16) -#define DEFAULT_AUDIO_IN_CHANNEL_NBR ((uint8_t)2) -#define DEFAULT_AUDIO_IN_VOLUME ((uint16_t)64) - -/*------------------------------------------------------------------------------ - OUTPUT DEVICES definition -------------------------------------------------------------------------------*/ -/* Alias on existing output devices to adapt for 2 headphones output */ -#define OUTPUT_DEVICE_HEADPHONE1 OUTPUT_DEVICE_HEADPHONE -#define OUTPUT_DEVICE_HEADPHONE2 OUTPUT_DEVICE_SPEAKER /* Headphone2 is connected to Speaker output of the wm8994 */ - -/*------------------------------------------------------------------------------ - INPUT DEVICES definition -------------------------------------------------------------------------------*/ -/* Analog microphone input from 3.5 audio jack connector */ -#define INPUT_DEVICE_ANALOG_MIC ((uint32_t)0x00000001) -/* MP34DT01TR digital microphone on PCB top side */ -#define INPUT_DEVICE_DIGITAL_MIC1 ((uint32_t)0x00000010) -#define INPUT_DEVICE_DIGITAL_MIC2 ((uint32_t)0x00000020) -#define INPUT_DEVICE_DIGITAL_MIC ((uint32_t)(INPUT_DEVICE_DIGITAL_MIC1 | INPUT_DEVICE_DIGITAL_MIC2)) - -/* Audio In interface for Digital mic */ -#define AUDIO_IN_INTERFACE_SAI ((uint16_t)0) -#define AUDIO_IN_INTERFACE_PDM ((uint16_t)1) - -/** - * @} - */ - -/** @defgroup STM32H747I_DISCOVERY_AUDIO_Exported_Macros Exported Macros - * @{ - */ -#define DMA_MAX_SIZE 0xFFFF -#define DMA_MAX(x) (((x) <= DMA_MAX_SIZE)? (x):DMA_MAX_SIZE) -#define POS_VAL(VAL) (POSITION_VAL(VAL) - 4) -/** - * @} - */ - -/** @addtogroup STM32H747I_DISCOVERY_AUDIO_OUT_Exported_Functions - * @{ - */ -uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq); -void BSP_AUDIO_OUT_DeInit(void); -uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size); -void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size); -uint8_t BSP_AUDIO_OUT_Pause(void); -uint8_t BSP_AUDIO_OUT_Resume(void); -uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option); -uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume); -void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq); -void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot); -uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd); -uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output); - -/* User Callbacks: user has to implement these functions in his code if they are needed. */ -/* This function is called when the requested data has been completely transferred.*/ -void BSP_AUDIO_OUT_TransferComplete_CallBack(void); - -/* This function is called when half of the requested buffer has been transferred. */ -void BSP_AUDIO_OUT_HalfTransfer_CallBack(void); - -/* This function is called when an Interrupt due to transfer error on or peripheral - error occurs. */ -void BSP_AUDIO_OUT_Error_CallBack(void); - -/* These function can be modified in case the current settings (e.g. DMA stream) - need to be changed for specific application needs */ -void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params); -void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params); -void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params); - -/** - * @} - */ - -/** @addtogroup STM32H747I_DISCOVERY_AUDIO_IN_Exported_Functions - * @{ - */ -uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); -uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); -uint8_t BSP_AUDIO_IN_AllocScratch (int32_t *pScratch, uint32_t size); -uint8_t BSP_AUDIO_IN_Record(uint16_t *pBuf, uint32_t Size); -uint8_t BSP_AUDIO_IN_RecordEx(uint32_t *pBuf, uint32_t Size); -uint8_t BSP_AUDIO_IN_SetFrequency(uint32_t AudioFreq); -uint8_t BSP_AUDIO_IN_Stop(void); -uint8_t BSP_AUDIO_IN_StopEx(uint32_t InputDevice); -uint8_t BSP_AUDIO_IN_Pause(void); -uint8_t BSP_AUDIO_IN_PauseEx(uint32_t InputDevice); -uint8_t BSP_AUDIO_IN_Resume(void); -uint8_t BSP_AUDIO_IN_ResumeEx(uint32_t *pBuf, uint32_t InputDevice); -uint8_t BSP_AUDIO_IN_SetVolume(uint8_t Volume); -void BSP_AUDIO_IN_DeInit(void); -uint8_t BSP_AUDIO_IN_PDMToPCM(uint16_t *PDMBuf, uint16_t *PCMBuf); -uint8_t BSP_AUDIO_IN_PDMToPCM_Init(uint32_t AudioFreq, uint32_t ChnlNbrIn, uint32_t ChnlNbrOut); -void BSP_AUDIO_IN_SelectInterface(uint32_t Interface); -uint32_t BSP_AUDIO_IN_GetInterface(void); -uint8_t BSP_AUDIO_IN_OUT_Init(uint32_t InputDevice, uint32_t OutputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr); -uint8_t BSP_AUDIO_IN_GetChannelNumber(void); -void BSP_AUDIO_IN_Error_Callback(void); - -/* User Callbacks: user has to implement these functions in his code if they are needed. */ -/* This function should be implemented by the user application. - It is called into this driver when the current buffer is filled to prepare the next - buffer pointer and its size. */ -void BSP_AUDIO_IN_TransferComplete_CallBack(void); -void BSP_AUDIO_IN_HalfTransfer_CallBack(void); -void BSP_AUDIO_IN_TransferComplete_CallBackEx(uint32_t InputDevice); -void BSP_AUDIO_IN_HalfTransfer_CallBackEx(uint32_t InputDevice); - -/* This function is called when an Interrupt due to transfer error on or peripheral - error occurs. */ -void BSP_AUDIO_IN_Error_CallBack(void); - -/* These function can be modified in case the current settings (e.g. DMA stream) - need to be changed for specific application needs */ -void BSP_AUDIO_IN_ClockConfig(uint32_t AudioFreq, void *Params); -void BSP_AUDIO_IN_MspInit(void); -void BSP_AUDIO_IN_MspDeInit(void); +#define PDM_BUFFER_SIZE (16384/2) +void py_audio_deinit(); +int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float highpass); +void audio_pendsv_callback(void); +void py_audio_start_streaming(); +void py_audio_stop_streaming(); bool isBoardRev2(); -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32H747I_DISCOVERY_AUDIO_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ +#endif \ No newline at end of file diff --git a/libraries/PDM/src/stm32/codec_api.h b/libraries/PDM/src/stm32/codec_api.h deleted file mode 100644 index 8b93673ff..000000000 --- a/libraries/PDM/src/stm32/codec_api.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - ****************************************************************************** - * @file audio.h - * @author MCD Application Team - * @version V4.0.1 - * @date 21-July-2015 - * @brief This header file contains the common defines and functions prototypes - * for the Audio driver. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2015 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __AUDIO_H -#define __AUDIO_H - -#ifdef __cplusplus - extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include - -/** @addtogroup BSP - * @{ - */ - -/** @addtogroup Components - * @{ - */ - -/** @addtogroup AUDIO - * @{ - */ - -/** @defgroup AUDIO_Exported_Constants - * @{ - */ - -/* Codec audio Standards */ -#define CODEC_STANDARD 0x04 -#define I2S_STANDARD I2S_STANDARD_PHILIPS - -/** - * @} - */ - -/** @defgroup AUDIO_Exported_Types - * @{ - */ - -/** @defgroup AUDIO_Driver_structure Audio Driver structure - * @{ - */ -typedef struct -{ - uint32_t (*Init)(uint16_t, uint16_t, uint8_t, uint32_t); - void (*DeInit)(void); - uint32_t (*ReadID)(uint16_t); - uint32_t (*Play)(uint16_t, uint16_t*, uint16_t); - uint32_t (*Pause)(uint16_t); - uint32_t (*Resume)(uint16_t); - uint32_t (*Stop)(uint16_t, uint32_t); - uint32_t (*SetFrequency)(uint16_t, uint32_t); - uint32_t (*SetVolume)(uint16_t, uint8_t); - uint32_t (*SetMute)(uint16_t, uint32_t); - uint32_t (*SetOutputMode)(uint16_t, uint8_t); - uint32_t (*Reset)(uint16_t); -}AUDIO_DrvTypeDef; -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __AUDIO_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/libraries/PDM/src/stm32/irq.c b/libraries/PDM/src/stm32/irq.c deleted file mode 100644 index cb7042f1b..000000000 --- a/libraries/PDM/src/stm32/irq.c +++ /dev/null @@ -1,28 +0,0 @@ -#ifdef TARGET_STM - -#include "audio.h" - -extern SAI_HandleTypeDef haudio_out_sai; -extern SAI_HandleTypeDef haudio_in_sai; - -void DMA2_Stream6_IRQHandler(void) -{ - HAL_DMA_IRQHandler(haudio_out_sai.hdmatx); -} - -void AUDIO_OUT_SAIx_DMAx_IRQHandler(void) -{ - HAL_DMA_IRQHandler(haudio_out_sai.hdmatx); -} - -/** - * @brief This function handles BDMA Channel 1 for SAI_PDM interrupt request. - * @param None - * @retval None - */ -void AUDIO_IN_SAI_PDMx_DMAx_IRQHandler(void) -{ - HAL_DMA_IRQHandler(haudio_in_sai.hdmarx); -} - -#endif \ No newline at end of file diff --git a/libraries/PDM/src/stm32/wm8994.c b/libraries/PDM/src/stm32/wm8994.c deleted file mode 100644 index fa6371a72..000000000 --- a/libraries/PDM/src/stm32/wm8994.c +++ /dev/null @@ -1,1043 +0,0 @@ -/** - ****************************************************************************** - * @file wm8994.c - * @author MCD Application Team - * @version V2.1.0 - * @date 22-February-2016 - * @brief This file provides the WM8994 Audio Codec driver. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -#ifdef TARGET_STM -/* Includes ------------------------------------------------------------------*/ -#include "wm8994.h" - -/** @addtogroup BSP - * @{ - */ - -/** @addtogroup Components - * @{ - */ - -/** @addtogroup wm8994 - * @brief This file provides a set of functions needed to drive the - * WM8994 audio codec. - * @{ - */ - -/** @defgroup WM8994_Private_Types - * @{ - */ - -/** - * @} - */ - -/** @defgroup WM8994_Private_Defines - * @{ - */ -/* Uncomment this line to enable verifying data sent to codec after each write - operation (for debug purpose) */ -#if !defined (VERIFY_WRITTENDATA) -/*#define VERIFY_WRITTENDATA*/ -#endif /* VERIFY_WRITTENDATA */ -/** - * @} - */ - -/** @defgroup WM8994_Private_Macros - * @{ - */ - -/** - * @} - */ - -/** @defgroup WM8994_Private_Variables - * @{ - */ - -/* Audio codec driver structure initialization */ -AUDIO_DrvTypeDef wm8994_drv = -{ - wm8994_Init, - wm8994_DeInit, - wm8994_ReadID, - - wm8994_Play, - wm8994_Pause, - wm8994_Resume, - wm8994_Stop, - - wm8994_SetFrequency, - wm8994_SetVolume, - wm8994_SetMute, - wm8994_SetOutputMode, - - wm8994_Reset -}; - -static uint32_t outputEnabled = 0; -static uint32_t inputEnabled = 0; -/** - * @} - */ - -/** @defgroup WM8994_Function_Prototypes - * @{ - */ -static uint8_t CODEC_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); -/** - * @} - */ - -/** @defgroup WM8994_Private_Functions - * @{ - */ - -/** - * @brief Initializes the audio codec and the control interface. - * @param DeviceAddr: Device address on communication Bus. - * @param OutputInputDevice: can be OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE, - * OUTPUT_DEVICE_BOTH, OUTPUT_DEVICE_AUTO, INPUT_DEVICE_DIGITAL_MICROPHONE_1, - * INPUT_DEVICE_DIGITAL_MICROPHONE_2, INPUT_DEVICE_DIGITAL_MIC1_MIC2, - * INPUT_DEVICE_INPUT_LINE_1 or INPUT_DEVICE_INPUT_LINE_2. - * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max)) - * @param AudioFreq: Audio Frequency - * @retval 0 if correct communication, else wrong communication - */ -uint32_t wm8994_Init(uint16_t DeviceAddr, uint16_t OutputInputDevice, uint8_t Volume, uint32_t AudioFreq) -{ - uint32_t counter = 0; - uint16_t output_device = OutputInputDevice & 0xFF; - uint16_t input_device = OutputInputDevice & 0xFF00; - uint16_t power_mgnt_reg_1 = 0; - - /* Initialize the Control interface of the Audio Codec */ - AUDIO_IO_Init(); - /* wm8994 Errata Work-Arounds */ - counter += CODEC_IO_Write(DeviceAddr, 0x102, 0x0003); - counter += CODEC_IO_Write(DeviceAddr, 0x817, 0x0000); - counter += CODEC_IO_Write(DeviceAddr, 0x102, 0x0000); - - /* Enable VMID soft start (fast), Start-up Bias Current Enabled */ - counter += CODEC_IO_Write(DeviceAddr, 0x39, 0x006C); - - /* Enable bias generator, Enable VMID */ - if (input_device > 0) - { - counter += CODEC_IO_Write(DeviceAddr, 0x01, 0x0013); - } - else - { - counter += CODEC_IO_Write(DeviceAddr, 0x01, 0x0003); - } - - /* Add Delay */ - AUDIO_IO_Delay(50); - - /* Path Configurations for output */ - if (output_device > 0) - { - outputEnabled = 1; - switch (output_device) - { - case OUTPUT_DEVICE_SPEAKER: - /* Enable DAC1 (Left), Enable DAC1 (Right), - Disable DAC2 (Left), Disable DAC2 (Right)*/ - counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0C0C); - - /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0000); - - /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0000); - - /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002); - - /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002); - break; - - case OUTPUT_DEVICE_HEADPHONE: - /* Disable DAC1 (Left), Disable DAC1 (Right), - Enable DAC2 (Left), Enable DAC2 (Right)*/ - counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303); - - /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); - - /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); - - /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000); - - /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000); - break; - - case OUTPUT_DEVICE_BOTH: - if (input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2) - { - /* Enable DAC1 (Left), Enable DAC1 (Right), - also Enable DAC2 (Left), Enable DAC2 (Right)*/ - counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303 | 0x0C0C); - - /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path - Enable the AIF1 Timeslot 1 (Left) to DAC 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0003); - - /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path - Enable the AIF1 Timeslot 1 (Right) to DAC 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0003); - - /* Enable the AIF1 Timeslot 0 (Left) to DAC 2 (Left) mixer path - Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0003); - - /* Enable the AIF1 Timeslot 0 (Right) to DAC 2 (Right) mixer path - Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0003); - } - else - { - /* Enable DAC1 (Left), Enable DAC1 (Right), - also Enable DAC2 (Left), Enable DAC2 (Right)*/ - counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303 | 0x0C0C); - - /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); - - /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); - - /* Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002); - - /* Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002); - } - break; - - case OUTPUT_DEVICE_AUTO : - default: - /* Disable DAC1 (Left), Disable DAC1 (Right), - Enable DAC2 (Left), Enable DAC2 (Right)*/ - counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303); - - /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); - - /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); - - /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000); - - /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000); - break; - } - } - else - { - outputEnabled = 0; - } - - /* Path Configurations for input */ - if (input_device > 0) - { - inputEnabled = 1; - switch (input_device) - { - case INPUT_DEVICE_DIGITAL_MICROPHONE_2 : - /* Enable AIF1ADC2 (Left), Enable AIF1ADC2 (Right) - * Enable DMICDAT2 (Left), Enable DMICDAT2 (Right) - * Enable Left ADC, Enable Right ADC */ - counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x0C30); - - /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC2 Left/Right Timeslot 1 */ - counter += CODEC_IO_Write(DeviceAddr, 0x450, 0x00DB); - - /* Disable IN1L, IN1R, IN2L, IN2R, Enable Thermal sensor & shutdown */ - counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x6000); - - /* Enable the DMIC2(Left) to AIF1 Timeslot 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x608, 0x0002); - - /* Enable the DMIC2(Right) to AIF1 Timeslot 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x609, 0x0002); - - /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC2 signal detect */ - counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000E); - break; - - case INPUT_DEVICE_INPUT_LINE_1 : - /* IN1LN_TO_IN1L, IN1LP_TO_VMID, IN1RN_TO_IN1R, IN1RP_TO_VMID */ - counter += CODEC_IO_Write(DeviceAddr, 0x28, 0x0011); - - /* Disable mute on IN1L_TO_MIXINL and +30dB on IN1L PGA output */ - counter += CODEC_IO_Write(DeviceAddr, 0x29, 0x0035); - - /* Disable mute on IN1R_TO_MIXINL, Gain = +30dB */ - counter += CODEC_IO_Write(DeviceAddr, 0x2A, 0x0035); - - /* Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right) - * Enable Left ADC, Enable Right ADC */ - counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x0303); - - /* Enable AIF1 DRC1 Signal Detect & DRC in AIF1ADC1 Left/Right Timeslot 0 */ - counter += CODEC_IO_Write(DeviceAddr, 0x440, 0x00DB); - - /* Enable IN1L and IN1R, Disable IN2L and IN2R, Enable Thermal sensor & shutdown */ - counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x6350); - - /* Enable the ADCL(Left) to AIF1 Timeslot 0 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x606, 0x0002); - - /* Enable the ADCR(Right) to AIF1 Timeslot 0 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x607, 0x0002); - - /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 signal detect */ - counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000D); - break; - - case INPUT_DEVICE_DIGITAL_MICROPHONE_1 : - /* Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right) - * Enable DMICDAT1 (Left), Enable DMICDAT1 (Right) - * Enable Left ADC, Enable Right ADC */ - counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x030C); - - /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC1 Left/Right Timeslot 0 */ - counter += CODEC_IO_Write(DeviceAddr, 0x440, 0x00DB); - - /* Disable IN1L, IN1R, IN2L, IN2R, Enable Thermal sensor & shutdown */ - counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x6350); - - /* Enable the DMIC2(Left) to AIF1 Timeslot 0 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x606, 0x0002); - - /* Enable the DMIC2(Right) to AIF1 Timeslot 0 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x607, 0x0002); - - /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 signal detect */ - counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000D); - break; - case INPUT_DEVICE_DIGITAL_MIC1_MIC2 : - /* Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right) - * Enable DMICDAT1 (Left), Enable DMICDAT1 (Right) - * Enable Left ADC, Enable Right ADC */ - counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x0F3C); - - /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC2 Left/Right Timeslot 1 */ - counter += CODEC_IO_Write(DeviceAddr, 0x450, 0x00DB); - - /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC1 Left/Right Timeslot 0 */ - counter += CODEC_IO_Write(DeviceAddr, 0x440, 0x00DB); - - /* Disable IN1L, IN1R, Enable IN2L, IN2R, Thermal sensor & shutdown */ - counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x63A0); - - /* Enable the DMIC2(Left) to AIF1 Timeslot 0 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x606, 0x0002); - - /* Enable the DMIC2(Right) to AIF1 Timeslot 0 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x607, 0x0002); - - /* Enable the DMIC2(Left) to AIF1 Timeslot 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x608, 0x0002); - - /* Enable the DMIC2(Right) to AIF1 Timeslot 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x609, 0x0002); - - /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 signal detect */ - counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000D); - break; - case INPUT_DEVICE_INPUT_LINE_2 : - default: - /* Actually, no other input devices supported */ - counter++; - break; - } - } - else - { - inputEnabled = 0; - } - - /* Clock Configurations */ - switch (AudioFreq) - { - case AUDIO_FREQUENCY_8K: - /* AIF1 Sample Rate = 8 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0003); - break; - - case AUDIO_FREQUENCY_16K: - /* AIF1 Sample Rate = 16 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0033); - break; - - case AUDIO_FREQUENCY_32K: - /* AIF1 Sample Rate = 32 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0063); - break; - - case AUDIO_FREQUENCY_48K: - /* AIF1 Sample Rate = 48 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083); - break; - - case AUDIO_FREQUENCY_96K: - /* AIF1 Sample Rate = 96 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x00A3); - break; - - case AUDIO_FREQUENCY_11K: - /* AIF1 Sample Rate = 11.025 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0013); - break; - - case AUDIO_FREQUENCY_22K: - /* AIF1 Sample Rate = 22.050 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0043); - break; - - case AUDIO_FREQUENCY_44K: - /* AIF1 Sample Rate = 44.1 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0073); - break; - - default: - /* AIF1 Sample Rate = 48 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083); - break; - } - - if(input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2) - { - /* AIF1 Word Length = 16-bits, AIF1 Format = DSP mode */ - counter += CODEC_IO_Write(DeviceAddr, 0x300, 0x4018); - } - else - { - /* AIF1 Word Length = 16-bits, AIF1 Format = I2S (Default Register Value) */ - counter += CODEC_IO_Write(DeviceAddr, 0x300, 0x4010); - } - - /* slave mode */ - counter += CODEC_IO_Write(DeviceAddr, 0x302, 0x0000); - - /* Enable the DSP processing clock for AIF1, Enable the core clock */ - counter += CODEC_IO_Write(DeviceAddr, 0x208, 0x000A); - - /* Enable AIF1 Clock, AIF1 Clock Source = MCLK1 pin */ - counter += CODEC_IO_Write(DeviceAddr, 0x200, 0x0001); - - if (output_device > 0) /* Audio output selected */ - { - /* Analog Output Configuration */ - - /* Enable SPKRVOL PGA, Enable SPKMIXR, Enable SPKLVOL PGA, Enable SPKMIXL */ - counter += CODEC_IO_Write(DeviceAddr, 0x03, 0x0300); - - /* Left Speaker Mixer Volume = 0dB */ - counter += CODEC_IO_Write(DeviceAddr, 0x22, 0x0000); - - /* Speaker output mode = Class D, Right Speaker Mixer Volume = 0dB ((0x23, 0x0100) = class AB)*/ - counter += CODEC_IO_Write(DeviceAddr, 0x23, 0x0000); - - /* Unmute DAC2 (Left) to Left Speaker Mixer (SPKMIXL) path, - Unmute DAC2 (Right) to Right Speaker Mixer (SPKMIXR) path */ - counter += CODEC_IO_Write(DeviceAddr, 0x36, 0x0300); - - /* Enable bias generator, Enable VMID, Enable SPKOUTL, Enable SPKOUTR */ - counter += CODEC_IO_Write(DeviceAddr, 0x01, 0x3003); - - /* Headphone/Speaker Enable */ - - if (input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2) - { - /* Enable Class W, Class W Envelope Tracking = AIF1 Timeslots 0 and 1 */ - counter += CODEC_IO_Write(DeviceAddr, 0x51, 0x0205); - } - else - { - /* Enable Class W, Class W Envelope Tracking = AIF1 Timeslot 0 */ - counter += CODEC_IO_Write(DeviceAddr, 0x51, 0x0005); - } - - /* Enable bias generator, Enable VMID, Enable HPOUT1 (Left) and Enable HPOUT1 (Right) input stages */ - /* idem for Speaker */ - power_mgnt_reg_1 |= 0x0303 | 0x3003; - counter += CODEC_IO_Write(DeviceAddr, 0x01, power_mgnt_reg_1); - - /* Enable HPOUT1 (Left) and HPOUT1 (Right) intermediate stages */ - counter += CODEC_IO_Write(DeviceAddr, 0x60, 0x0022); - - /* Enable Charge Pump */ - counter += CODEC_IO_Write(DeviceAddr, 0x4C, 0x9F25); - - /* Add Delay */ - AUDIO_IO_Delay(15); - - /* Select DAC1 (Left) to Left Headphone Output PGA (HPOUT1LVOL) path */ - counter += CODEC_IO_Write(DeviceAddr, 0x2D, 0x0001); - - /* Select DAC1 (Right) to Right Headphone Output PGA (HPOUT1RVOL) path */ - counter += CODEC_IO_Write(DeviceAddr, 0x2E, 0x0001); - - /* Enable Left Output Mixer (MIXOUTL), Enable Right Output Mixer (MIXOUTR) */ - /* idem for SPKOUTL and SPKOUTR */ - counter += CODEC_IO_Write(DeviceAddr, 0x03, 0x0030 | 0x0300); - - /* Enable DC Servo and trigger start-up mode on left and right channels */ - counter += CODEC_IO_Write(DeviceAddr, 0x54, 0x0033); - - /* Add Delay */ - AUDIO_IO_Delay(250); - - /* Enable HPOUT1 (Left) and HPOUT1 (Right) intermediate and output stages. Remove clamps */ - counter += CODEC_IO_Write(DeviceAddr, 0x60, 0x00EE); - - /* Unmutes */ - - /* Unmute DAC 1 (Left) */ - counter += CODEC_IO_Write(DeviceAddr, 0x610, 0x00C0); - - /* Unmute DAC 1 (Right) */ - counter += CODEC_IO_Write(DeviceAddr, 0x611, 0x00C0); - - /* Unmute the AIF1 Timeslot 0 DAC path */ - counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0000); - - /* Unmute DAC 2 (Left) */ - counter += CODEC_IO_Write(DeviceAddr, 0x612, 0x00C0); - - /* Unmute DAC 2 (Right) */ - counter += CODEC_IO_Write(DeviceAddr, 0x613, 0x00C0); - - /* Unmute the AIF1 Timeslot 1 DAC2 path */ - counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0000); - - /* Volume Control */ - wm8994_SetVolume(DeviceAddr, Volume); - } - - if (input_device > 0) /* Audio input selected */ - { - if ((input_device == INPUT_DEVICE_DIGITAL_MICROPHONE_1) || (input_device == INPUT_DEVICE_DIGITAL_MICROPHONE_2)) - { - /* Enable Microphone bias 1 generator, Enable VMID */ - power_mgnt_reg_1 |= 0x0013; - counter += CODEC_IO_Write(DeviceAddr, 0x01, power_mgnt_reg_1); - - /* ADC oversample enable */ - counter += CODEC_IO_Write(DeviceAddr, 0x620, 0x0002); - - /* AIF ADC2 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz */ - counter += CODEC_IO_Write(DeviceAddr, 0x411, 0x3800); - } - else if(input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2) - { - /* Enable Microphone bias 1 generator, Enable VMID */ - power_mgnt_reg_1 |= 0x0013; - counter += CODEC_IO_Write(DeviceAddr, 0x01, power_mgnt_reg_1); - - /* ADC oversample enable */ - counter += CODEC_IO_Write(DeviceAddr, 0x620, 0x0002); - - /* AIF ADC1 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz */ - counter += CODEC_IO_Write(DeviceAddr, 0x410, 0x1800); - - /* AIF ADC2 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz */ - counter += CODEC_IO_Write(DeviceAddr, 0x411, 0x1800); - } - else if ((input_device == INPUT_DEVICE_INPUT_LINE_1) || (input_device == INPUT_DEVICE_INPUT_LINE_2)) - { - - /* Disable mute on IN1L, IN1L Volume = +0dB */ - counter += CODEC_IO_Write(DeviceAddr, 0x18, 0x000B); - - /* Disable mute on IN1R, IN1R Volume = +0dB */ - counter += CODEC_IO_Write(DeviceAddr, 0x1A, 0x000B); - - /* AIF ADC1 HPF enable, HPF cut = hifi mode fc=4Hz at fs=48kHz */ - counter += CODEC_IO_Write(DeviceAddr, 0x410, 0x1800); - } - /* Volume Control */ - wm8994_SetVolume(DeviceAddr, Volume); - } - /* Return communication control value */ - return counter; -} - -/** - * @brief Deinitializes the audio codec. - * @param None - * @retval None - */ -void wm8994_DeInit(void) -{ - /* Deinitialize Audio Codec interface */ - AUDIO_IO_DeInit(); -} - -/** - * @brief Get the WM8994 ID. - * @param DeviceAddr: Device address on communication Bus. - * @retval The WM8994 ID - */ -uint32_t wm8994_ReadID(uint16_t DeviceAddr) -{ - /* Initialize the Control interface of the Audio Codec */ - AUDIO_IO_Init(); - - return ((uint32_t)AUDIO_IO_Read(DeviceAddr, WM8994_CHIPID_ADDR)); -} - -/** - * @brief Start the audio Codec play feature. - * @note For this codec no Play options are required. - * @param DeviceAddr: Device address on communication Bus. - * @retval 0 if correct communication, else wrong communication - */ -uint32_t wm8994_Play(uint16_t DeviceAddr, uint16_t* pBuffer, uint16_t Size) -{ - uint32_t counter = 0; - - /* Resumes the audio file playing */ - /* Unmute the output first */ - counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF); - - return counter; -} - -/** - * @brief Pauses playing on the audio codec. - * @param DeviceAddr: Device address on communication Bus. - * @retval 0 if correct communication, else wrong communication - */ -uint32_t wm8994_Pause(uint16_t DeviceAddr) -{ - uint32_t counter = 0; - - /* Pause the audio file playing */ - /* Mute the output first */ - counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_ON); - - /* Put the Codec in Power save mode */ - counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x01); - - return counter; -} - -/** - * @brief Resumes playing on the audio codec. - * @param DeviceAddr: Device address on communication Bus. - * @retval 0 if correct communication, else wrong communication - */ -uint32_t wm8994_Resume(uint16_t DeviceAddr) -{ - uint32_t counter = 0; - - /* Resumes the audio file playing */ - /* Unmute the output first */ - counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF); - - return counter; -} - -/** - * @brief Stops audio Codec playing. It powers down the codec. - * @param DeviceAddr: Device address on communication Bus. - * @param CodecPdwnMode: selects the power down mode. - * - CODEC_PDWN_SW: only mutes the audio codec. When resuming from this - * mode the codec keeps the previous initialization - * (no need to re-Initialize the codec registers). - * - CODEC_PDWN_HW: Physically power down the codec. When resuming from this - * mode, the codec is set to default configuration - * (user should re-Initialize the codec in order to - * play again the audio stream). - * @retval 0 if correct communication, else wrong communication - */ -uint32_t wm8994_Stop(uint16_t DeviceAddr, uint32_t CodecPdwnMode) -{ - uint32_t counter = 0; - - if (outputEnabled != 0) - { - /* Mute the output first */ - counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_ON); - - if (CodecPdwnMode == CODEC_PDWN_SW) - { - /* Only output mute required*/ - } - else /* CODEC_PDWN_HW */ - { - /* Mute the AIF1 Timeslot 0 DAC1 path */ - counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0200); - - /* Mute the AIF1 Timeslot 1 DAC2 path */ - counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0200); - - /* Disable DAC1L_TO_HPOUT1L */ - counter += CODEC_IO_Write(DeviceAddr, 0x2D, 0x0000); - - /* Disable DAC1R_TO_HPOUT1R */ - counter += CODEC_IO_Write(DeviceAddr, 0x2E, 0x0000); - - /* Disable DAC1 and DAC2 */ - counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0000); - - /* Reset Codec by writing in 0x0000 address register */ - counter += CODEC_IO_Write(DeviceAddr, 0x0000, 0x0000); - - outputEnabled = 0; - } - } - return counter; -} - -/** - * @brief Sets higher or lower the codec volume level. - * @param DeviceAddr: Device address on communication Bus. - * @param Volume: a byte value from 0 to 255 (refer to codec registers - * description for more details). - * @retval 0 if correct communication, else wrong communication - */ -uint32_t wm8994_SetVolume(uint16_t DeviceAddr, uint8_t Volume) -{ - uint32_t counter = 0; - uint8_t convertedvol = VOLUME_CONVERT(Volume); - - /* Output volume */ - if (outputEnabled != 0) - { - if(convertedvol > 0x3E) - { - /* Unmute audio codec */ - counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF); - - /* Left Headphone Volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x1C, 0x3F | 0x140); - - /* Right Headphone Volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x1D, 0x3F | 0x140); - - /* Left Speaker Volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x26, 0x3F | 0x140); - - /* Right Speaker Volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x27, 0x3F | 0x140); - } - else if (Volume == 0) - { - /* Mute audio codec */ - counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_ON); - } - else - { - /* Unmute audio codec */ - counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF); - - /* Left Headphone Volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x1C, convertedvol | 0x140); - - /* Right Headphone Volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x1D, convertedvol | 0x140); - - /* Left Speaker Volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x26, convertedvol | 0x140); - - /* Right Speaker Volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x27, convertedvol | 0x140); - } - } - - /* Input volume */ - if (inputEnabled != 0) - { - convertedvol = VOLUME_IN_CONVERT(Volume); - - /* Left AIF1 ADC1 volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x400, convertedvol | 0x100); - - /* Right AIF1 ADC1 volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x401, convertedvol | 0x100); - - /* Left AIF1 ADC2 volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x404, convertedvol | 0x100); - - /* Right AIF1 ADC2 volume */ - counter += CODEC_IO_Write(DeviceAddr, 0x405, convertedvol | 0x100); - } - return counter; -} - -/** - * @brief Enables or disables the mute feature on the audio codec. - * @param DeviceAddr: Device address on communication Bus. - * @param Cmd: AUDIO_MUTE_ON to enable the mute or AUDIO_MUTE_OFF to disable the - * mute mode. - * @retval 0 if correct communication, else wrong communication - */ -uint32_t wm8994_SetMute(uint16_t DeviceAddr, uint32_t Cmd) -{ - uint32_t counter = 0; - - if (outputEnabled != 0) - { - /* Set the Mute mode */ - if(Cmd == AUDIO_MUTE_ON) - { - /* Soft Mute the AIF1 Timeslot 0 DAC1 path L&R */ - counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0200); - - /* Soft Mute the AIF1 Timeslot 1 DAC2 path L&R */ - counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0200); - } - else /* AUDIO_MUTE_OFF Disable the Mute */ - { - /* Unmute the AIF1 Timeslot 0 DAC1 path L&R */ - counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0000); - - /* Unmute the AIF1 Timeslot 1 DAC2 path L&R */ - counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0000); - } - } - return counter; -} - -/** - * @brief Switch dynamically (while audio file is played) the output target - * (speaker or headphone). - * @param DeviceAddr: Device address on communication Bus. - * @param Output: specifies the audio output target: OUTPUT_DEVICE_SPEAKER, - * OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO - * @retval 0 if correct communication, else wrong communication - */ -uint32_t wm8994_SetOutputMode(uint16_t DeviceAddr, uint8_t Output) -{ - uint32_t counter = 0; - - switch (Output) - { - case OUTPUT_DEVICE_SPEAKER: - /* Enable DAC1 (Left), Enable DAC1 (Right), - Disable DAC2 (Left), Disable DAC2 (Right)*/ - counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0C0C); - - /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0000); - - /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0000); - - /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002); - - /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002); - break; - - case OUTPUT_DEVICE_HEADPHONE: - /* Disable DAC1 (Left), Disable DAC1 (Right), - Enable DAC2 (Left), Enable DAC2 (Right)*/ - counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303); - - /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); - - /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); - - /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000); - - /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000); - break; - - case OUTPUT_DEVICE_BOTH: - /* Enable DAC1 (Left), Enable DAC1 (Right), - also Enable DAC2 (Left), Enable DAC2 (Right)*/ - counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303 | 0x0C0C); - - /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); - - /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); - - /* Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002); - - /* Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002); - break; - - default: - /* Disable DAC1 (Left), Disable DAC1 (Right), - Enable DAC2 (Left), Enable DAC2 (Right)*/ - counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303); - - /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001); - - /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001); - - /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000); - - /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */ - counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000); - break; - } - return counter; -} - -/** - * @brief Sets new frequency. - * @param DeviceAddr: Device address on communication Bus. - * @param AudioFreq: Audio frequency used to play the audio stream. - * @retval 0 if correct communication, else wrong communication - */ -uint32_t wm8994_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq) -{ - uint32_t counter = 0; - - /* Clock Configurations */ - switch (AudioFreq) - { - case AUDIO_FREQUENCY_8K: - /* AIF1 Sample Rate = 8 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0003); - break; - - case AUDIO_FREQUENCY_16K: - /* AIF1 Sample Rate = 16 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0033); - break; - - case AUDIO_FREQUENCY_48K: - /* AIF1 Sample Rate = 48 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083); - break; - - case AUDIO_FREQUENCY_96K: - /* AIF1 Sample Rate = 96 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x00A3); - break; - - case AUDIO_FREQUENCY_11K: - /* AIF1 Sample Rate = 11.025 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0013); - break; - - case AUDIO_FREQUENCY_22K: - /* AIF1 Sample Rate = 22.050 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0043); - break; - - case AUDIO_FREQUENCY_44K: - /* AIF1 Sample Rate = 44.1 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0073); - break; - - default: - /* AIF1 Sample Rate = 48 (KHz), ratio=256 */ - counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083); - break; - } - return counter; -} - -/** - * @brief Resets wm8994 registers. - * @param DeviceAddr: Device address on communication Bus. - * @retval 0 if correct communication, else wrong communication - */ -uint32_t wm8994_Reset(uint16_t DeviceAddr) -{ - uint32_t counter = 0; - - /* Reset Codec by writing in 0x0000 address register */ - counter = CODEC_IO_Write(DeviceAddr, 0x0000, 0x0000); - outputEnabled = 0; - inputEnabled=0; - - return counter; -} - -/** - * @brief Writes/Read a single data. - * @param Addr: I2C address - * @param Reg: Reg address - * @param Value: Data to be written - * @retval None - */ -static uint8_t CODEC_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value) -{ - uint32_t result = 0; - - AUDIO_IO_Write(Addr, Reg, Value); - -#ifdef VERIFY_WRITTENDATA - /* Verify that the data has been correctly written */ - result = (AUDIO_IO_Read(Addr, Reg) == Value)? 0:1; -#endif /* VERIFY_WRITTENDATA */ - - return result; -} - -#endif -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/libraries/PDM/src/stm32/wm8994.h b/libraries/PDM/src/stm32/wm8994.h deleted file mode 100644 index c4d625b32..000000000 --- a/libraries/PDM/src/stm32/wm8994.h +++ /dev/null @@ -1,188 +0,0 @@ -/** - ****************************************************************************** - * @file wm8994.h - * @author MCD Application Team - * @version V2.1.0 - * @date 22-February-2016 - * @brief This file contains all the functions prototypes for the - * wm8994.c driver. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __WM8994_H -#define __WM8994_H - -/* Includes ------------------------------------------------------------------*/ -#include "codec_api.h" - -/** @addtogroup BSP - * @{ - */ - -/** @addtogroup Component - * @{ - */ - -/** @addtogroup WM8994 - * @{ - */ - -/** @defgroup WM8994_Exported_Types - * @{ - */ - -/** - * @} - */ - -/** @defgroup WM8994_Exported_Constants - * @{ - */ - -/******************************************************************************/ -/*************************** Codec User defines ******************************/ -/******************************************************************************/ -/* Codec output DEVICE */ -#define OUTPUT_DEVICE_SPEAKER ((uint16_t)0x0001) -#define OUTPUT_DEVICE_HEADPHONE ((uint16_t)0x0002) -#define OUTPUT_DEVICE_BOTH ((uint16_t)0x0003) -#define OUTPUT_DEVICE_AUTO ((uint16_t)0x0004) -#define INPUT_DEVICE_DIGITAL_MICROPHONE_1 ((uint16_t)0x0100) -#define INPUT_DEVICE_DIGITAL_MICROPHONE_2 ((uint16_t)0x0200) -#define INPUT_DEVICE_INPUT_LINE_1 ((uint16_t)0x0300) -#define INPUT_DEVICE_INPUT_LINE_2 ((uint16_t)0x0400) -#define INPUT_DEVICE_DIGITAL_MIC1_MIC2 ((uint16_t)0x0800) - -/* Volume Levels values */ -#define DEFAULT_VOLMIN 0x00 -#define DEFAULT_VOLMAX 0xFF -#define DEFAULT_VOLSTEP 0x04 - -#define AUDIO_PAUSE 0 -#define AUDIO_RESUME 1 - -/* Codec POWER DOWN modes */ -#define CODEC_PDWN_HW 1 -#define CODEC_PDWN_SW 2 - -/* MUTE commands */ -#define AUDIO_MUTE_ON 1 -#define AUDIO_MUTE_OFF 0 - -/* AUDIO FREQUENCY */ -#define AUDIO_FREQUENCY_192K ((uint32_t)192000) -#define AUDIO_FREQUENCY_96K ((uint32_t)96000) -#define AUDIO_FREQUENCY_48K ((uint32_t)48000) -#define AUDIO_FREQUENCY_44K ((uint32_t)44100) -#define AUDIO_FREQUENCY_32K ((uint32_t)32000) -#define AUDIO_FREQUENCY_22K ((uint32_t)22050) -#define AUDIO_FREQUENCY_16K ((uint32_t)16000) -#define AUDIO_FREQUENCY_11K ((uint32_t)11025) -#define AUDIO_FREQUENCY_8K ((uint32_t)8000) - -#define VOLUME_CONVERT(Volume) (((Volume) > 100)? 100:((uint8_t)(((Volume) * 63) / 100))) -#define VOLUME_IN_CONVERT(Volume) (((Volume) >= 100)? 239:((uint8_t)(((Volume) * 240) / 100))) - -/******************************************************************************/ -/****************************** REGISTER MAPPING ******************************/ -/******************************************************************************/ -/** - * @brief WM8994 ID - */ -#define WM8994_ID 0x8994 - -/** - * @brief Device ID Register: Reading from this register will indicate device - * family ID 8994h - */ -#define WM8994_CHIPID_ADDR 0x00 - -/** - * @} - */ - -/** @defgroup WM8994_Exported_Macros - * @{ - */ -/** - * @} - */ - -/** @defgroup WM8994_Exported_Functions - * @{ - */ - -/*------------------------------------------------------------------------------ - Audio Codec functions -------------------------------------------------------------------------------*/ -/* High Layer codec functions */ -uint32_t wm8994_Init(uint16_t DeviceAddr, uint16_t OutputInputDevice, uint8_t Volume, uint32_t AudioFreq); -void wm8994_DeInit(void); -uint32_t wm8994_ReadID(uint16_t DeviceAddr); -uint32_t wm8994_Play(uint16_t DeviceAddr, uint16_t* pBuffer, uint16_t Size); -uint32_t wm8994_Pause(uint16_t DeviceAddr); -uint32_t wm8994_Resume(uint16_t DeviceAddr); -uint32_t wm8994_Stop(uint16_t DeviceAddr, uint32_t Cmd); -uint32_t wm8994_SetVolume(uint16_t DeviceAddr, uint8_t Volume); -uint32_t wm8994_SetMute(uint16_t DeviceAddr, uint32_t Cmd); -uint32_t wm8994_SetOutputMode(uint16_t DeviceAddr, uint8_t Output); -uint32_t wm8994_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq); -uint32_t wm8994_Reset(uint16_t DeviceAddr); - -/* AUDIO IO functions */ -void AUDIO_IO_Init(void); -void AUDIO_IO_DeInit(void); -void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value); -uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg); -void AUDIO_IO_Delay(uint32_t Delay); - -/* Audio driver structure */ -extern AUDIO_DrvTypeDef wm8994_drv; - -#endif /* __WM8994_H */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/libraries/PDM/src/utility/PDMDoubleBuffer.cpp b/libraries/PDM/src/utility/PDMDoubleBuffer.cpp index 15bd9cad2..2e6a4c2c7 100644 --- a/libraries/PDM/src/utility/PDMDoubleBuffer.cpp +++ b/libraries/PDM/src/utility/PDMDoubleBuffer.cpp @@ -34,6 +34,7 @@ PDMDoubleBuffer::~PDMDoubleBuffer() void PDMDoubleBuffer::setSize(int size) { _size = size; + reset(); } void PDMDoubleBuffer::reset() diff --git a/libraries/PDM/src/utility/PDMDoubleBuffer.h b/libraries/PDM/src/utility/PDMDoubleBuffer.h index e410b62d7..1544af5bf 100644 --- a/libraries/PDM/src/utility/PDMDoubleBuffer.h +++ b/libraries/PDM/src/utility/PDMDoubleBuffer.h @@ -43,7 +43,7 @@ class PDMDoubleBuffer void swap(int length = 0); private: - uint8_t* _buffer[2]; + uint8_t* _buffer[2] __attribute__((aligned (16))); int _size; volatile int _length[2]; volatile int _readOffset[2]; From 05777282cf5fa9c3fcbdc493cfc29c14a02ff11a Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 24 Feb 2021 17:22:54 +0100 Subject: [PATCH 2/8] Fixed PDM::Begin return value --- libraries/PDM/src/stm32/PDM.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/PDM/src/stm32/PDM.cpp b/libraries/PDM/src/stm32/PDM.cpp index b17548661..f6786d8b5 100644 --- a/libraries/PDM/src/stm32/PDM.cpp +++ b/libraries/PDM/src/stm32/PDM.cpp @@ -71,11 +71,11 @@ int PDMClass::begin(int channels, long sampleRate) { //g_pcmbuf = (uint16_t*)_doubleBuffer.data(); - py_audio_init(channels, sampleRate, gain_db, 0.9883f); - - py_audio_start_streaming(); - - return 1; + if(py_audio_init(channels, sampleRate, gain_db, 0.9883f)) { + py_audio_start_streaming(); + return 1; + } + return 0; } void PDMClass::end() @@ -139,4 +139,4 @@ void PDMsetBufferSize(int size) { PDMClass PDM(0, 0, 0); -#endif \ No newline at end of file +#endif From c44ef020232ffe3fd6c850a6c0b59b1c74e7072e Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 24 Feb 2021 12:30:38 +0100 Subject: [PATCH 3/8] Configure MCK_DIV according sampling frequency with fixed decimation factor --- libraries/PDM/src/stm32/audio.c | 63 ++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/libraries/PDM/src/stm32/audio.c b/libraries/PDM/src/stm32/audio.c index 6878956dc..83295a51f 100644 --- a/libraries/PDM/src/stm32/audio.c +++ b/libraries/PDM/src/stm32/audio.c @@ -29,6 +29,19 @@ static PDM_Filter_Config_t PDM_FilterConfig[2]; #define DMA_XFER_NONE (0x00U) #define DMA_XFER_HALF (0x01U) #define DMA_XFER_FULL (0x04U) + +#define AUDIO_FREQUENCY_192K ((uint32_t)192000) +#define AUDIO_FREQUENCY_96K ((uint32_t)96000) +#define AUDIO_FREQUENCY_64K ((uint32_t)64000) +#define AUDIO_FREQUENCY_48K ((uint32_t)48000) +#define AUDIO_FREQUENCY_44K ((uint32_t)44100) +#define AUDIO_FREQUENCY_32K ((uint32_t)32000) +#define AUDIO_FREQUENCY_22K ((uint32_t)22050) +#define AUDIO_FREQUENCY_16K ((uint32_t)16000) +#define AUDIO_FREQUENCY_11K ((uint32_t)11025) +#define AUDIO_FREQUENCY_8K ((uint32_t)8000) + + static volatile uint32_t xfer_status = 0; // BDMA can only access D3 SRAM4 memory. @@ -70,15 +83,21 @@ static uint32_t get_decimation_factor(uint32_t decimation) } } -#define AUDIO_FREQUENCY_192K ((uint32_t)192000) -#define AUDIO_FREQUENCY_96K ((uint32_t)96000) -#define AUDIO_FREQUENCY_48K ((uint32_t)48000) -#define AUDIO_FREQUENCY_44K ((uint32_t)44100) -#define AUDIO_FREQUENCY_32K ((uint32_t)32000) -#define AUDIO_FREQUENCY_22K ((uint32_t)22050) -#define AUDIO_FREQUENCY_16K ((uint32_t)16000) -#define AUDIO_FREQUENCY_11K ((uint32_t)11025) -#define AUDIO_FREQUENCY_8K ((uint32_t)8000) + +static uint8_t get_mck_div(uint32_t frequency) +{ + switch(frequency){ + case AUDIO_FREQUENCY_8K: return 48; //SCK_x = sai_x_ker_ck/48 = 1024KHz Ffs = SCK_x/64 = 16KHz stereo + case AUDIO_FREQUENCY_16K: return 24; //SCK_x = sai_x_ker_ck/24 = 2048KHz Ffs = SCK_x/64 = 32KHz stereo + case AUDIO_FREQUENCY_32K: return 12; //SCK_x = sai_x_ker_ck/12 = 4096KHz Ffs = SCK_x/64 = 64KHz stereo + case AUDIO_FREQUENCY_48K: return 8; //SCK_x = sai_x_ker_ck/8 = 6144KHz Ffs = SCK_x/64 = 96KHz stereo + case AUDIO_FREQUENCY_64K: return 6; //SCK_x = sai_x_ker_ck/6 = 8192KHz Ffs = SCK_x/64 = 128KHz stereo + case AUDIO_FREQUENCY_96K: return 4; //SCK_x = sai_x_ker_ck/4 = 12288KHz Ffs = SCK_x/64 = 192KHz stereo + case AUDIO_FREQUENCY_192K: return 2; //SCK_x = sai_x_ker_ck/2 = 24576KHz Ffs = SCK_x/64 = 384KHz stereo + default: return 0; //Same as 1 + } +} + // TODO: this needs to become a library function bool isBoardRev2() { @@ -124,22 +143,26 @@ int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float high /* SAI clock config: PLL2_VCO Input = HSE_VALUE/PLL2M = 1 Mhz PLL2_VCO Output = PLL2_VCO Input * PLL2N = 344 Mhz - SAI_CLK_x = PLL2_VCO Output/PLL2P = 344/7 = 49.142 Mhz */ - rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI1; - rcc_ex_clk_init_struct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLL2; + sai_x_ker_ck = PLL2_VCO Output/PLL2P = 344/7 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI4A; + rcc_ex_clk_init_struct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL2; rcc_ex_clk_init_struct.PLL2.PLL2P = 7; rcc_ex_clk_init_struct.PLL2.PLL2Q = 1; rcc_ex_clk_init_struct.PLL2.PLL2R = 1; rcc_ex_clk_init_struct.PLL2.PLL2N = 344; - rcc_ex_clk_init_struct.PLL2.PLL2M = 25; - rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI4A; - rcc_ex_clk_init_struct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL2; + rcc_ex_clk_init_struct.PLL2.PLL2M = isBoardRev2() ? 25 : 27; + HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); sai_init(); // Sanity checks - if (frequency < 16000 || frequency > 128000) { + if ((frequency != AUDIO_FREQUENCY_8K) && + (frequency != AUDIO_FREQUENCY_16K) && + (frequency != AUDIO_FREQUENCY_32K) && + (frequency != AUDIO_FREQUENCY_48K) && + (frequency != AUDIO_FREQUENCY_64K) && + (frequency != AUDIO_FREQUENCY_96K)){ return 0; } @@ -147,7 +170,7 @@ int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float high return 0; } - uint32_t decimation_factor = AUDIO_SAI_FREQKHZ / (frequency / 1000); + uint32_t decimation_factor = 64; // Fixed decimation factor uint32_t decimation_factor_const = get_decimation_factor(decimation_factor); if (decimation_factor_const == 0) { return 0; @@ -171,8 +194,8 @@ int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float high hsai.Init.TriState = SAI_OUTPUT_RELEASED; // The master clock output (MCLK_x) is disabled and the SAI clock - // is passed out to SCK_x bit clock. SCKx frequency = SAI_KER_CK / MCKDIV / 2 - hsai.Init.Mckdiv = AUDIO_SAI_MCKDIV; //2.048MHz + // is passed out to SCK_x bit clock. SCKx frequency = SAI_KER_CK / MCKDIV + hsai.Init.Mckdiv = get_mck_div(frequency); hsai.Init.MckOutput = SAI_MCK_OUTPUT_DISABLE; hsai.Init.MckOverSampling = SAI_MCK_OVERSAMPLING_DISABLE; @@ -314,7 +337,7 @@ void py_audio_start_streaming() // Start DMA transfer if (HAL_SAI_Receive_DMA(&hsai, (uint8_t*) PDM_BUFFER, PDM_BUFFER_SIZE / g_channels) != HAL_OK) { - + } } From 87c15a3b095850f0843efd17dd53fc427ba83d34 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 26 Feb 2021 09:20:54 +0100 Subject: [PATCH 4/8] Increased default gain to 24db --- libraries/PDM/src/stm32/PDM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/PDM/src/stm32/PDM.cpp b/libraries/PDM/src/stm32/PDM.cpp index f6786d8b5..f34fbc5f4 100644 --- a/libraries/PDM/src/stm32/PDM.cpp +++ b/libraries/PDM/src/stm32/PDM.cpp @@ -66,7 +66,7 @@ int PDMClass::begin(int channels, long sampleRate) { _samplerate = sampleRate; if (gain_db == -1) { - gain_db = -10; + gain_db = 24; } //g_pcmbuf = (uint16_t*)_doubleBuffer.data(); From a216699bc4096fbe5c25d410ef111af1fe40d2e2 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 25 Feb 2021 11:59:22 +0100 Subject: [PATCH 5/8] Split input and output channels number --- libraries/PDM/src/stm32/audio.c | 42 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/libraries/PDM/src/stm32/audio.c b/libraries/PDM/src/stm32/audio.c index 83295a51f..623842764 100644 --- a/libraries/PDM/src/stm32/audio.c +++ b/libraries/PDM/src/stm32/audio.c @@ -22,7 +22,8 @@ static DMA_HandleTypeDef hdma_sai_rx; volatile uint16_t *g_pcmbuf = NULL; -static int g_channels = AUDIO_SAI_NBR_CHANNELS; +static int g_i_channels = AUDIO_SAI_NBR_CHANNELS; +static int g_o_channels = AUDIO_SAI_NBR_CHANNELS; static PDM_Filter_Handler_t PDM_FilterHandler[2]; static PDM_Filter_Config_t PDM_FilterConfig[2]; @@ -133,7 +134,7 @@ void sai_init() HAL_GPIO_Init(AUDIO_SAI_D1_PORT, &GPIO_InitStruct); } -int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float highpass) +int py_audio_init(size_t channels, uint32_t frequency, int gain_db, float highpass) { RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct; @@ -166,8 +167,10 @@ int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float high return 0; } - if (g_channels != 1 && g_channels != 2) { + if (channels != 1 && channels != 2) { return 0; + } else { + g_o_channels = channels; } uint32_t decimation_factor = 64; // Fixed decimation factor @@ -175,12 +178,12 @@ int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float high if (decimation_factor_const == 0) { return 0; } - uint32_t samples_per_channel = (PDM_BUFFER_SIZE * 8) / (decimation_factor * g_channels * 2); // Half a transfer + uint32_t samples_per_channel = (PDM_BUFFER_SIZE * 8) / (decimation_factor * g_i_channels * 2); // Half a transfer hsai.Instance = AUDIO_SAI; hsai.Init.Protocol = SAI_FREE_PROTOCOL; hsai.Init.AudioMode = SAI_MODEMASTER_RX; - hsai.Init.DataSize = (g_channels == 1) ? SAI_DATASIZE_8 : SAI_DATASIZE_16; + hsai.Init.DataSize = (g_i_channels == 1) ? SAI_DATASIZE_8 : SAI_DATASIZE_16; hsai.Init.FirstBit = SAI_FIRSTBIT_LSB; hsai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; hsai.Init.Synchro = SAI_ASYNCHRONOUS; @@ -189,7 +192,7 @@ int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float high hsai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; hsai.Init.SynchroExt = SAI_SYNCEXT_DISABLE; hsai.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_MCKDIV; - hsai.Init.MonoStereoMode = (g_channels == 1) ? SAI_MONOMODE: SAI_STEREOMODE; + hsai.Init.MonoStereoMode = (g_i_channels == 1) ? SAI_MONOMODE: SAI_STEREOMODE; hsai.Init.CompandingMode = SAI_NOCOMPANDING; hsai.Init.TriState = SAI_OUTPUT_RELEASED; @@ -212,8 +215,8 @@ int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float high hsai.SlotInit.FirstBitOffset = 0; hsai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; - hsai.SlotInit.SlotNumber = (g_channels == 1) ? 2 : 1; - hsai.SlotInit.SlotActive = (g_channels == 1) ? (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1) : SAI_SLOTACTIVE_0; + hsai.SlotInit.SlotNumber = (g_i_channels == 1) ? 2 : 1; + hsai.SlotInit.SlotActive = (g_i_channels == 1) ? (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1) : SAI_SLOTACTIVE_0; // Initialize the SAI HAL_SAI_DeInit(&hsai); @@ -230,8 +233,8 @@ int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float high hdma_sai_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_sai_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_sai_rx.Init.MemInc = DMA_MINC_ENABLE; - hdma_sai_rx.Init.PeriphDataAlignment = (g_channels == 1) ? DMA_PDATAALIGN_BYTE : DMA_PDATAALIGN_HALFWORD; - hdma_sai_rx.Init.MemDataAlignment = (g_channels == 1) ? DMA_MDATAALIGN_BYTE : DMA_MDATAALIGN_HALFWORD; + hdma_sai_rx.Init.PeriphDataAlignment = (g_i_channels == 1) ? DMA_PDATAALIGN_BYTE : DMA_PDATAALIGN_HALFWORD; + hdma_sai_rx.Init.MemDataAlignment = (g_i_channels == 1) ? DMA_MDATAALIGN_BYTE : DMA_MDATAALIGN_HALFWORD; hdma_sai_rx.Init.Mode = DMA_CIRCULAR; hdma_sai_rx.Init.Priority = DMA_PRIORITY_HIGH; hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; @@ -263,12 +266,12 @@ int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float high __HAL_CRC_DR_RESET(&hcrc); // Configure PDM filters - for (int i=0; i Date: Mon, 1 Mar 2021 14:26:53 +0100 Subject: [PATCH 6/8] Add support to 11kHz 22kHz and 44kHz sampling rate --- libraries/PDM/src/stm32/audio.c | 44 ++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/libraries/PDM/src/stm32/audio.c b/libraries/PDM/src/stm32/audio.c index 623842764..f6bf95c08 100644 --- a/libraries/PDM/src/stm32/audio.c +++ b/libraries/PDM/src/stm32/audio.c @@ -89,8 +89,11 @@ static uint8_t get_mck_div(uint32_t frequency) { switch(frequency){ case AUDIO_FREQUENCY_8K: return 48; //SCK_x = sai_x_ker_ck/48 = 1024KHz Ffs = SCK_x/64 = 16KHz stereo + case AUDIO_FREQUENCY_11K: return 8; //SCK_x = sai_x_ker_ck/8 = 1411KHz Ffs = SCK_x/64 = 22KHz stereo case AUDIO_FREQUENCY_16K: return 24; //SCK_x = sai_x_ker_ck/24 = 2048KHz Ffs = SCK_x/64 = 32KHz stereo + case AUDIO_FREQUENCY_22K: return 4; //SCK_x = sai_x_ker_ck/4 = 2822KHz Ffs = SCK_x/64 = 44KHz stereo case AUDIO_FREQUENCY_32K: return 12; //SCK_x = sai_x_ker_ck/12 = 4096KHz Ffs = SCK_x/64 = 64KHz stereo + case AUDIO_FREQUENCY_44K: return 2; //SCK_x = sai_x_ker_ck/2 = 5644KHz Ffs = SCK_x/64 = 88KHz stereo case AUDIO_FREQUENCY_48K: return 8; //SCK_x = sai_x_ker_ck/8 = 6144KHz Ffs = SCK_x/64 = 96KHz stereo case AUDIO_FREQUENCY_64K: return 6; //SCK_x = sai_x_ker_ck/6 = 8192KHz Ffs = SCK_x/64 = 128KHz stereo case AUDIO_FREQUENCY_96K: return 4; //SCK_x = sai_x_ker_ck/4 = 12288KHz Ffs = SCK_x/64 = 192KHz stereo @@ -141,17 +144,33 @@ int py_audio_init(size_t channels, uint32_t frequency, int gain_db, float highpa HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct); - /* SAI clock config: - PLL2_VCO Input = HSE_VALUE/PLL2M = 1 Mhz - PLL2_VCO Output = PLL2_VCO Input * PLL2N = 344 Mhz - sai_x_ker_ck = PLL2_VCO Output/PLL2P = 344/7 = 49.142 Mhz */ - rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI4A; - rcc_ex_clk_init_struct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL2; - rcc_ex_clk_init_struct.PLL2.PLL2P = 7; - rcc_ex_clk_init_struct.PLL2.PLL2Q = 1; - rcc_ex_clk_init_struct.PLL2.PLL2R = 1; - rcc_ex_clk_init_struct.PLL2.PLL2N = 344; - rcc_ex_clk_init_struct.PLL2.PLL2M = isBoardRev2() ? 25 : 27; + if((frequency == AUDIO_FREQUENCY_11K) || (frequency == AUDIO_FREQUENCY_22K) || (frequency == AUDIO_FREQUENCY_44K)) + { + /* SAI clock config: + PLL2_VCO Input = HSE_VALUE/PLL2M = 1 Mhz + PLL2_VCO Output = PLL2_VCO Input * PLL2N = 429 Mhz + SAI_CLK_x = PLL2_VCO Output/PLL2P = 429/38 = 11.289 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI4A; + rcc_ex_clk_init_struct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL2; + rcc_ex_clk_init_struct.PLL2.PLL2P = 38; + rcc_ex_clk_init_struct.PLL2.PLL2Q = 1; + rcc_ex_clk_init_struct.PLL2.PLL2R = 1; + rcc_ex_clk_init_struct.PLL2.PLL2N = 429; + rcc_ex_clk_init_struct.PLL2.PLL2M = isBoardRev2() ? 25 : 27; + + } else { + /* SAI clock config: + PLL2_VCO Input = HSE_VALUE/PLL2M = 1 Mhz + PLL2_VCO Output = PLL2_VCO Input * PLL2N = 344 Mhz + sai_x_ker_ck = PLL2_VCO Output/PLL2P = 344/7 = 49.142 Mhz */ + rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI4A; + rcc_ex_clk_init_struct.Sai4AClockSelection = RCC_SAI4ACLKSOURCE_PLL2; + rcc_ex_clk_init_struct.PLL2.PLL2P = 7; + rcc_ex_clk_init_struct.PLL2.PLL2Q = 1; + rcc_ex_clk_init_struct.PLL2.PLL2R = 1; + rcc_ex_clk_init_struct.PLL2.PLL2N = 344; + rcc_ex_clk_init_struct.PLL2.PLL2M = isBoardRev2() ? 25 : 27; + } HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct); @@ -159,8 +178,11 @@ int py_audio_init(size_t channels, uint32_t frequency, int gain_db, float highpa // Sanity checks if ((frequency != AUDIO_FREQUENCY_8K) && + (frequency != AUDIO_FREQUENCY_11K) && (frequency != AUDIO_FREQUENCY_16K) && + (frequency != AUDIO_FREQUENCY_22K) && (frequency != AUDIO_FREQUENCY_32K) && + (frequency != AUDIO_FREQUENCY_44K) && (frequency != AUDIO_FREQUENCY_48K) && (frequency != AUDIO_FREQUENCY_64K) && (frequency != AUDIO_FREQUENCY_96K)){ From 353bec51321d75f9d34cf6f4552f76117d02ab7f Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 3 Mar 2021 09:46:06 +0100 Subject: [PATCH 7/8] Reduce PDM buffer to 1KB --- libraries/PDM/src/stm32/audio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/PDM/src/stm32/audio.h b/libraries/PDM/src/stm32/audio.h index 398254964..08d7d60b8 100644 --- a/libraries/PDM/src/stm32/audio.h +++ b/libraries/PDM/src/stm32/audio.h @@ -28,7 +28,7 @@ #define AUDIO_IN_IRQ_PREPRIO ((uint32_t)0x0F) -#define PDM_BUFFER_SIZE (16384/2) +#define PDM_BUFFER_SIZE (1024) void py_audio_deinit(); int py_audio_init(size_t g_channels, uint32_t frequency, int gain_db, float highpass); @@ -37,4 +37,4 @@ void py_audio_start_streaming(); void py_audio_stop_streaming(); bool isBoardRev2(); -#endif \ No newline at end of file +#endif From 8ed5830499116c9d741d4672cae224a551694fbe Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 3 Mar 2021 11:27:06 +0100 Subject: [PATCH 8/8] Use linker script section to allocate PDM_BUFFER --- libraries/PDM/src/stm32/audio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/PDM/src/stm32/audio.c b/libraries/PDM/src/stm32/audio.c index f6bf95c08..f52aaa6e8 100644 --- a/libraries/PDM/src/stm32/audio.c +++ b/libraries/PDM/src/stm32/audio.c @@ -46,7 +46,8 @@ static PDM_Filter_Config_t PDM_FilterConfig[2]; static volatile uint32_t xfer_status = 0; // BDMA can only access D3 SRAM4 memory. -int8_t* PDM_BUFFER = (uint16_t*)0x38000000; +//int8_t* PDM_BUFFER = (uint16_t*)0x38000000; +uint8_t PDM_BUFFER[PDM_BUFFER_SIZE] __attribute__ ((section(".pdm_buffer"))); void PDMIrqHandler(bool halftranfer); void PDMsetBufferSize(int size);