BSP driver for DISCO_L496AG
Dependents: DISCO_L496AG-LCD-prova_1 DISCO_L496AG-LCD-prova_2 DISCO_L496AG-LCD-demo DISCO_L496AG-SRAM-demo
Drivers/BSP/Components/cs42l51/cs42l51.c
- Committer:
- Jerome Coutant
- Date:
- 2019-11-20
- Revision:
- 2:106c7b82e064
- Parent:
- 0:d83f1c8ca282
File content as of revision 2:106c7b82e064:
/** ****************************************************************************** * @file cs42l51.c * @author MCD Application Team * @brief This file provides the CS42L51 Audio Codec driver. ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2017 STMicroelectronics. * All rights reserved.</center></h2> * * 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 * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "cs42l51.h" /** @addtogroup BSP * @{ */ /** @addtogroup Components * @{ */ /** @addtogroup CS42L51 * @brief This file provides a set of functions needed to drive the * CS42L51 audio codec. * @{ */ /** @defgroup CS42L51_Exported_Variables * @{ */ /* Audio codec driver structure initialization */ AUDIO_DrvTypeDef cs42l51_drv = { cs42l51_Init, cs42l51_DeInit, cs42l51_ReadID, cs42l51_Play, cs42l51_Pause, cs42l51_Resume, cs42l51_Stop, cs42l51_SetFrequency, cs42l51_SetVolume, cs42l51_SetMute, cs42l51_SetOutputMode, cs42l51_Reset, }; /** * @} */ /** @defgroup CS42L51_Private_Types * @{ */ /** * @} */ /** @defgroup CS42L51_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 CS42L51_Private_Macros * @{ */ /** * @} */ /** @defgroup CS42L51_Private_Variables * @{ */ static uint8_t Is_CS42L51_Initialized = 0; static uint8_t Is_CS42L51_Stop = 1; static uint16_t CS42L51_Device = OUTPUT_DEVICE_HEADPHONE; /** * @} */ /** @defgroup CS42L51_Private_Functions * @{ */ static uint8_t CODEC_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value); /** * @} */ /** @addtogroup CS42L51_Exported_Functions * @{ */ /** * @brief Initialize the audio codec and the control interface. * @param DeviceAddr: Device address on communication bus. * @param Device: Can be combination values of OUTPUT_DEVICE_HEADPHONE and * INPUT_DEVICE_MIC1. * @param Volume: Initial output volume level (from 0 (-100dB) to 100 (0dB)). * @param AudioFreq: Initial audio frequency (currently not used). * @retval 0 if correct communication, else wrong communication. */ uint32_t cs42l51_Init(uint16_t DeviceAddr, uint16_t Device, uint8_t Volume, uint32_t AudioFreq) { uint32_t counter = 0; uint8_t Value; /* Check if codec is already initialized */ if(Is_CS42L51_Initialized == 0) { /* Initialize the Control interface of the Audio Codec */ AUDIO_IO_Init(); Is_CS42L51_Initialized = 1; } else { /* Set all power down bits to 1 exept PDN to mute ADCs and DACs*/ counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x7E); Value = AUDIO_IO_Read(DeviceAddr, 0x03); counter += CODEC_IO_Write(DeviceAddr, 0x03, (Value | 0x0E)); /* Disable zero cross and soft ramp */ Value = AUDIO_IO_Read(DeviceAddr, 0x09); counter += CODEC_IO_Write(DeviceAddr, 0x09, (Value & 0xFC)); /* Power control : Enter standby (PDN = 1) */ Value = AUDIO_IO_Read(DeviceAddr, 0x02); counter += CODEC_IO_Write(DeviceAddr, 0x02, (Value | 0x01)); } /* Mic Power and Speed Control : Auto detect on, Speed mode SSM, tri state off, MCLK divide by 2 off */ Value = AUDIO_IO_Read(DeviceAddr, 0x03); counter += CODEC_IO_Write(DeviceAddr, 0x03, ((Value & 0x0E) | 0xA0)); /* Interface control : Loopback off, Slave, I2S (SDIN and SOUT), Digital mix off, Mic mix off */ counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x0C); /* Mic control : ADC single volume off, ADCB boost off, ADCA boost off, MicBias on AIN3B/MICIN2 pin, MicBias level 0.8xVA, MICB boost 16db, MICA boost 16dB */ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x00); /* ADC control : ADCB HPF off, ADCB HPF freeze off, ADCA HPF off, ADCA HPF freeze off, Soft ramp B off, Zero cross B off, Soft ramp A off, Zero cross A off */ counter += CODEC_IO_Write(DeviceAddr, 0x06, 0x00); /* ADC Input Select, Invert and Mute : AIN1B to PGAB, AIN3A to PreAmp to PGAA, ADCB invert off, ADCA invert off, ADCB mute on, ADCA mute off */ counter += CODEC_IO_Write(DeviceAddr, 0x07, 0x32); /* DAC output control : HP Gain to 1, Single volume control off, PCM invert signals polarity off, DAC channels mute on */ counter += CODEC_IO_Write(DeviceAddr, 0x08, 0xC3); /* DAC control : Signal processing to DAC, Freeze off, De-emphasis off, Analog output auto mute off, DAC soft ramp */ counter += CODEC_IO_Write(DeviceAddr, 0x09, 0x42); /* ALCA and PGAA Control : ALCA soft ramp disable on, ALCA zero cross disable on, PGA A Gain 0dB */ counter += CODEC_IO_Write(DeviceAddr, 0x0A, 0xC0); /* ALCB and PGAB Control : ALCB soft ramp disable on, ALCB zero cross disable on, PGA B Gain 0dB */ counter += CODEC_IO_Write(DeviceAddr, 0x0B, 0xC0); /* ADCA Attenuator : 0dB */ counter += CODEC_IO_Write(DeviceAddr, 0x0C, 0x00); /* ADCB Attenuator : 0dB */ counter += CODEC_IO_Write(DeviceAddr, 0x0D, 0x00); /* ADCA mixer volume control : ADCA mixer channel mute on, ADCA mixer volume 0dB */ counter += CODEC_IO_Write(DeviceAddr, 0x0E, 0x80); /* ADCB mixer volume control : ADCB mixer channel mute on, ADCB mixer volume 0dB */ counter += CODEC_IO_Write(DeviceAddr, 0x0F, 0x80); /* PCMA mixer volume control : PCMA mixer channel mute off, PCMA mixer volume 0dB */ counter += CODEC_IO_Write(DeviceAddr, 0x10, 0x00); /* PCMB mixer volume control : PCMB mixer channel mute off, PCMB mixer volume 0dB */ counter += CODEC_IO_Write(DeviceAddr, 0x11, 0x00); /* PCM channel mixer : AOUTA Left, AOUTB Right */ counter += CODEC_IO_Write(DeviceAddr, 0x18, 0x00); if(Device & OUTPUT_DEVICE_HEADPHONE) { Value = VOLUME_CONVERT(Volume); /* AOUTA volume control : AOUTA volume */ counter += CODEC_IO_Write(DeviceAddr, 0x16, Value); /* AOUTB volume control : AOUTB volume */ counter += CODEC_IO_Write(DeviceAddr, 0x17, Value); } /* Store device */ CS42L51_Device = Device; /* Return communication control value */ return counter; } /** * @brief Deinitialize the audio codec. * @param None * @retval None */ void cs42l51_DeInit(void) { /* Deinitialize Audio Codec interface */ AUDIO_IO_DeInit(); Is_CS42L51_Initialized = 0; } /** * @brief Get the CS42L51 ID. * @param DeviceAddr: Device address on communication Bus. * @retval The CS42L51 ID */ uint32_t cs42l51_ReadID(uint16_t DeviceAddr) { uint8_t Value; if(Is_CS42L51_Initialized == 0) { /* Initialize the Control interface of the Audio Codec */ AUDIO_IO_Init(); Value = AUDIO_IO_Read(DeviceAddr, CS42L51_CHIPID_ADDR); Value = (Value & CS42L51_ID_MASK); /* Deinitialize Audio Codec interface */ AUDIO_IO_DeInit(); } else { Value = AUDIO_IO_Read(DeviceAddr, CS42L51_CHIPID_ADDR); Value = (Value & CS42L51_ID_MASK); } return((uint32_t) Value); } /** * @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 cs42l51_Play(uint16_t DeviceAddr, uint16_t* pBuffer, uint16_t Size) { uint32_t counter = 0; uint8_t Value; if(Is_CS42L51_Stop == 1) { /* Unmute output device */ counter += cs42l51_SetMute(DeviceAddr, AUDIO_MUTE_OFF); if(CS42L51_Device & OUTPUT_DEVICE_HEADPHONE) { /* DAC control : Signal processing to DAC, Freeze off, De-emphasis off, Analog output auto mute off, DAC soft ramp */ counter += CODEC_IO_Write(DeviceAddr, 0x09, 0x42); /* Power control 1 : PDN_DACA, PDN_DACB disable. */ Value = AUDIO_IO_Read(DeviceAddr, 0x02); counter += CODEC_IO_Write(DeviceAddr, 0x02, (Value & 0x9F)); } if(CS42L51_Device & INPUT_DEVICE_MIC1) { /* Power control 1 : PDN_PGAA, PDN_ADCA disable. */ Value = AUDIO_IO_Read(DeviceAddr, 0x02); counter += CODEC_IO_Write(DeviceAddr, 0x02, (Value & 0xF5)); /* Mic Power and Speed Control : PDN_MICA, PDN_MIC_BIAS disable. */ Value = AUDIO_IO_Read(DeviceAddr, 0x03); counter += CODEC_IO_Write(DeviceAddr, 0x03, (Value & 0xF9)); } /* Power control : Exit standby (PDN = 0) */ Value = AUDIO_IO_Read(DeviceAddr, 0x02); counter += CODEC_IO_Write(DeviceAddr, 0x02, (Value & 0xFE)); Is_CS42L51_Stop = 0; } /* Return communication control value */ return counter; } /** * @brief Pause playing on the audio codec. * @param DeviceAddr: Device address on communication Bus. * @retval 0 if correct communication, else wrong communication */ uint32_t cs42l51_Pause(uint16_t DeviceAddr) { uint32_t counter = 0; /* Pause the audio file playing */ /* Mute the output first */ counter += cs42l51_SetMute(DeviceAddr, AUDIO_MUTE_ON); return counter; } /** * @brief Resume playing on the audio codec. * @param DeviceAddr: Device address on communication Bus. * @retval 0 if correct communication, else wrong communication */ uint32_t cs42l51_Resume(uint16_t DeviceAddr) { uint32_t counter = 0; /* Unmute the output */ counter += cs42l51_SetMute(DeviceAddr, AUDIO_MUTE_OFF); return counter; } /** * @brief Stop audio Codec playing. It powers down the codec. * @param DeviceAddr: Device address on communication Bus. * @param CodecPdwnMode: selects the power down mode (currently not used). * @retval 0 if correct communication, else wrong communication */ uint32_t cs42l51_Stop(uint16_t DeviceAddr, uint32_t CodecPdwnMode) { uint32_t counter = 0; uint8_t Value; /* Set all power down bits to 1 exept PDN to mute ADCs and DACs*/ counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x7E); Value = AUDIO_IO_Read(DeviceAddr, 0x03); counter += CODEC_IO_Write(DeviceAddr, 0x03, (Value | 0x0E)); /* Disable zero cross and soft ramp */ Value = AUDIO_IO_Read(DeviceAddr, 0x09); counter += CODEC_IO_Write(DeviceAddr, 0x09, (Value & 0xFC)); /* Power control : Enter standby (PDN = 1) */ Value = AUDIO_IO_Read(DeviceAddr, 0x02); counter += CODEC_IO_Write(DeviceAddr, 0x02, (Value | 0x01)); Is_CS42L51_Stop = 1; return counter; } /** * @brief Set higher or lower the codec volume level. * @param DeviceAddr: Device address on communication Bus. * @param Volume: output volume level (from 0 (-100dB) to 100 (0dB)). * @retval 0 if correct communication, else wrong communication */ uint32_t cs42l51_SetVolume(uint16_t DeviceAddr, uint8_t Volume) { uint32_t counter = 0; uint8_t convertedvol = VOLUME_CONVERT(Volume); /* AOUTA volume control : AOUTA volume */ counter += CODEC_IO_Write(DeviceAddr, 0x16, convertedvol); /* AOUTB volume control : AOUTB volume */ counter += CODEC_IO_Write(DeviceAddr, 0x17, convertedvol); return counter; } /** * @brief Set 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 cs42l51_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq) { return 0; } /** * @brief Enable or disable 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 cs42l51_SetMute(uint16_t DeviceAddr, uint32_t Cmd) { uint32_t counter = 0; uint8_t Value; /* Read DAC output control register */ Value = AUDIO_IO_Read(DeviceAddr, 0x08); /* Set the Mute mode */ if(Cmd == AUDIO_MUTE_ON) { /* Mute DAC channels */ counter += CODEC_IO_Write(DeviceAddr, 0x08, (Value | 0x03)); } else /* AUDIO_MUTE_OFF Disable the Mute */ { /* Unmute DAC channels */ counter += CODEC_IO_Write(DeviceAddr, 0x08, (Value & 0xFC)); } return counter; } /** * @brief Switch dynamically (while audio file is played) the output target * (speaker, headphone, etc). * @note This function is currently not used (only headphone output device). * @param DeviceAddr: Device address on communication Bus. * @param Output: specifies the audio output device target. * @retval 0 if correct communication, else wrong communication */ uint32_t cs42l51_SetOutputMode(uint16_t DeviceAddr, uint8_t Output) { return 0; } /** * @brief Reset CS42L51 registers. * @param DeviceAddr: Device address on communication Bus. * @retval 0 if correct communication, else wrong communication */ uint32_t cs42l51_Reset(uint16_t DeviceAddr) { if(Is_CS42L51_Initialized == 1) { /* Deinitialize Audio Codec interface */ AUDIO_IO_DeInit(); /* Initialize the Control interface of the Audio Codec */ AUDIO_IO_Init(); } return 0; } /** * @} */ /** @addtogroup CS42L51_Private_Functions * @{ */ /** * @brief Write and optionally read back 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, uint8_t Reg, uint8_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; } /** * @} */ /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/