ST / BSP_DISCO_F469NI

Dependents:   Configurable_Robots DISCO-F469NI_LCD_demo DISCO-F469NI_SD_demo DISCO-F469NI_EEPROM_demo ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers cs43l22.c Source File

cs43l22.c

Go to the documentation of this file.
00001 /**
00002   ******************************************************************************
00003   * @file    cs43l22.c
00004   * @author  MCD Application Team
00005   * @brief   This file provides the CS43L22 Audio Codec driver.   
00006   ******************************************************************************
00007   * @attention
00008   *
00009   * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
00010   *
00011   * Redistribution and use in source and binary forms, with or without modification,
00012   * are permitted provided that the following conditions are met:
00013   *   1. Redistributions of source code must retain the above copyright notice,
00014   *      this list of conditions and the following disclaimer.
00015   *   2. Redistributions in binary form must reproduce the above copyright notice,
00016   *      this list of conditions and the following disclaimer in the documentation
00017   *      and/or other materials provided with the distribution.
00018   *   3. Neither the name of STMicroelectronics nor the names of its contributors
00019   *      may be used to endorse or promote products derived from this software
00020   *      without specific prior written permission.
00021   *
00022   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00023   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00024   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00025   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00026   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00027   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00028   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00030   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00031   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032   *
00033   ******************************************************************************
00034   */
00035 
00036 /* Includes ------------------------------------------------------------------*/
00037 #include "cs43l22.h"
00038 
00039 /** @addtogroup BSP
00040   * @{
00041   */
00042   
00043 /** @addtogroup Components
00044   * @{
00045   */ 
00046 
00047 /** @addtogroup CS43L22
00048   * @brief     This file provides a set of functions needed to drive the 
00049   *            CS43L22 audio codec.
00050   * @{
00051   */
00052 
00053 /** @defgroup CS43L22_Private_Types
00054   * @{
00055   */
00056 
00057 /**
00058   * @}
00059   */ 
00060   
00061 /** @defgroup CS43L22_Private_Defines
00062   * @{
00063   */
00064 #define VOLUME_CONVERT(Volume)    (((Volume) > 100)? 255:((uint8_t)(((Volume) * 255) / 100)))  
00065 /* Uncomment this line to enable verifying data sent to codec after each write 
00066    operation (for debug purpose) */
00067 #if !defined (VERIFY_WRITTENDATA)  
00068 /* #define VERIFY_WRITTENDATA */
00069 #endif /* VERIFY_WRITTENDATA */
00070 /**
00071   * @}
00072   */ 
00073 
00074 /** @defgroup CS43L22_Private_Macros
00075   * @{
00076   */
00077 
00078 /**
00079   * @}
00080   */ 
00081   
00082 /** @defgroup CS43L22_Private_Variables
00083   * @{
00084   */
00085 
00086 /* Audio codec driver structure initialization */  
00087 AUDIO_DrvTypeDef cs43l22_drv = 
00088 {
00089   cs43l22_Init,
00090   cs43l22_DeInit,
00091   cs43l22_ReadID,
00092 
00093   cs43l22_Play,
00094   cs43l22_Pause,
00095   cs43l22_Resume,
00096   cs43l22_Stop,  
00097   
00098   cs43l22_SetFrequency,  
00099   cs43l22_SetVolume,
00100   cs43l22_SetMute,  
00101   cs43l22_SetOutputMode,
00102   cs43l22_Reset,
00103 };
00104 
00105 static uint8_t Is_cs43l22_Stop = 1;
00106 
00107 volatile uint8_t OutputDev = 0;
00108 
00109 /**
00110   * @}
00111   */ 
00112 
00113 /** @defgroup CS43L22_Function_Prototypes
00114   * @{
00115   */
00116 static uint8_t CODEC_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value);
00117 /**
00118   * @}
00119   */ 
00120 
00121 /** @defgroup CS43L22_Private_Functions
00122   * @{
00123   */ 
00124 
00125 /**
00126   * @brief Initializes the audio codec and the control interface.
00127   * @param DeviceAddr: Device address on communication Bus.   
00128   * @param OutputDevice: can be OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
00129   *                       OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO .
00130   * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max))
00131   * @retval 0 if correct communication, else wrong communication
00132   */
00133 uint32_t cs43l22_Init(uint16_t DeviceAddr, uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq)
00134 {
00135   uint32_t counter = 0;
00136   
00137   /* Initialize the Control interface of the Audio Codec */
00138   AUDIO_IO_Init();     
00139     
00140   /* Keep Codec powered OFF */
00141   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL1, 0x01);  
00142   
00143   /*Save Output device for mute ON/OFF procedure*/
00144   switch (OutputDevice)
00145   {
00146   case OUTPUT_DEVICE_SPEAKER:
00147     OutputDev = 0xFA;
00148     break;
00149     
00150   case OUTPUT_DEVICE_HEADPHONE:
00151     OutputDev = 0xAF;
00152     break;
00153     
00154   case OUTPUT_DEVICE_BOTH:
00155     OutputDev = 0xAA;
00156     break;
00157     
00158   case OUTPUT_DEVICE_AUTO:
00159     OutputDev = 0x05;
00160     break;    
00161     
00162   default:
00163     OutputDev = 0x05;
00164     break;    
00165   }
00166   
00167   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, OutputDev);
00168   
00169   /* Clock configuration: Auto detection */  
00170   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_CLOCKING_CTL, 0x81);
00171   
00172   /* Set the Slave Mode and the audio Standard */  
00173   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_INTERFACE_CTL1, CODEC_STANDARD);
00174   
00175   /* Set the Master volume */
00176   counter += cs43l22_SetVolume(DeviceAddr, Volume);
00177   
00178   /* If the Speaker is enabled, set the Mono mode and volume attenuation level */
00179   if(OutputDevice != OUTPUT_DEVICE_HEADPHONE)
00180   {
00181     /* Set the Speaker Mono mode */  
00182     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_PLAYBACK_CTL2, 0x06);
00183     
00184     /* Set the Speaker attenuation level */  
00185     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_SPEAKER_A_VOL, 0x00);
00186     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_SPEAKER_B_VOL, 0x00);
00187   }
00188   
00189   /* Additional configuration for the CODEC. These configurations are done to reduce
00190   the time needed for the Codec to power off. If these configurations are removed, 
00191   then a long delay should be added between powering off the Codec and switching 
00192   off the I2S peripheral MCLK clock (which is the operating clock for Codec).
00193   If this delay is not inserted, then the codec will not shut down properly and
00194   it results in high noise after shut down. */
00195   
00196   /* Disable the analog soft ramp */
00197   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_ANALOG_ZC_SR_SETT, 0x00);
00198   /* Disable the digital soft ramp */
00199   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MISC_CTL, 0x04);
00200   /* Disable the limiter attack level */
00201   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_LIMIT_CTL1, 0x00);
00202   /* Adjust Bass and Treble levels */
00203   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_TONE_CTL, 0x0F);
00204   /* Adjust PCM volume level */
00205   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_PCMA_VOL, 0x0A);
00206   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_PCMB_VOL, 0x0A);
00207   
00208   /* Return communication control value */
00209   return counter;  
00210 }
00211 
00212 /**
00213   * @brief  Deinitializes the audio codec.
00214   * @param  None
00215   * @retval  None
00216   */
00217 void cs43l22_DeInit(void)
00218 {
00219   /* Deinitialize Audio Codec interface */
00220   AUDIO_IO_DeInit();
00221 }
00222 
00223 /**
00224   * @brief  Get the CS43L22 ID.
00225   * @param DeviceAddr: Device address on communication Bus.   
00226   * @retval The CS43L22 ID 
00227   */
00228 uint32_t cs43l22_ReadID(uint16_t DeviceAddr)
00229 {
00230   uint8_t Value;
00231   /* Initialize the Control interface of the Audio Codec */
00232   AUDIO_IO_Init(); 
00233   
00234   Value = AUDIO_IO_Read(DeviceAddr, CS43L22_CHIPID_ADDR);
00235   Value = (Value & CS43L22_ID_MASK);
00236   
00237   return((uint32_t) Value);
00238 }
00239 
00240 /**
00241   * @brief Start the audio Codec play feature.
00242   * @note For this codec no Play options are required.
00243   * @param DeviceAddr: Device address on communication Bus.   
00244   * @retval 0 if correct communication, else wrong communication
00245   */
00246 uint32_t cs43l22_Play(uint16_t DeviceAddr, uint16_t* pBuffer, uint16_t Size)
00247 {
00248   uint32_t counter = 0;
00249   
00250   if(Is_cs43l22_Stop == 1)
00251   {
00252     /* Enable the digital soft ramp */
00253     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MISC_CTL, 0x06);
00254   
00255     /* Enable Output device */  
00256     counter += cs43l22_SetMute(DeviceAddr, AUDIO_MUTE_OFF);
00257     
00258     /* Power on the Codec */
00259     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL1, 0x9E);  
00260     Is_cs43l22_Stop = 0;
00261   }
00262   
00263   /* Return communication control value */
00264   return counter;  
00265 }
00266 
00267 /**
00268   * @brief Pauses playing on the audio codec.
00269   * @param DeviceAddr: Device address on communication Bus. 
00270   * @retval 0 if correct communication, else wrong communication
00271   */
00272 uint32_t cs43l22_Pause(uint16_t DeviceAddr)
00273 {  
00274   uint32_t counter = 0;
00275  
00276   /* Pause the audio file playing */
00277   /* Mute the output first */
00278   counter += cs43l22_SetMute(DeviceAddr, AUDIO_MUTE_ON);
00279   
00280   /* Put the Codec in Power save mode */    
00281   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL1, 0x01);
00282  
00283   return counter;
00284 }
00285 
00286 /**
00287   * @brief Resumes playing on the audio codec.
00288   * @param DeviceAddr: Device address on communication Bus. 
00289   * @retval 0 if correct communication, else wrong communication
00290   */
00291 uint32_t cs43l22_Resume(uint16_t DeviceAddr)
00292 {
00293   uint32_t counter = 0;
00294   volatile uint32_t index = 0x00;
00295   /* Resumes the audio file playing */  
00296   /* Unmute the output first */
00297   counter += cs43l22_SetMute(DeviceAddr, AUDIO_MUTE_OFF);
00298 
00299   for(index = 0x00; index < 0xFF; index++);
00300   
00301   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, OutputDev);
00302 
00303   /* Exit the Power save mode */
00304   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL1, 0x9E); 
00305   
00306   return counter;
00307 }
00308 
00309 /**
00310   * @brief Stops audio Codec playing. It powers down the codec.
00311   * @param DeviceAddr: Device address on communication Bus. 
00312   * @param CodecPdwnMode: selects the  power down mode.
00313   *          - CODEC_PDWN_HW: Physically power down the codec. When resuming from this
00314   *                           mode, the codec is set to default configuration 
00315   *                           (user should re-Initialize the codec in order to 
00316   *                            play again the audio stream).
00317   * @retval 0 if correct communication, else wrong communication
00318   */
00319 uint32_t cs43l22_Stop(uint16_t DeviceAddr, uint32_t CodecPdwnMode)
00320 {
00321   uint32_t counter = 0;
00322   
00323   /* Mute the output first */
00324   counter += cs43l22_SetMute(DeviceAddr, AUDIO_MUTE_ON);
00325 
00326   /* Disable the digital soft ramp */
00327   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MISC_CTL, 0x04);
00328   
00329   /* Power down the DAC and the speaker (PMDAC and PMSPK bits)*/
00330   counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL1, 0x9F);
00331   
00332   Is_cs43l22_Stop = 1;
00333   return counter;    
00334 }
00335 
00336 /**
00337   * @brief Sets higher or lower the codec volume level.
00338   * @param DeviceAddr: Device address on communication Bus.   
00339   * @param Volume: a byte value from 0 to 255 (refer to codec registers 
00340   *                description for more details).
00341   *         
00342   * @retval 0 if correct communication, else wrong communication
00343   */
00344 uint32_t cs43l22_SetVolume(uint16_t DeviceAddr, uint8_t Volume)
00345 {
00346   uint32_t counter = 0;
00347   uint8_t convertedvol = VOLUME_CONVERT(Volume);
00348 
00349   if(convertedvol > 0xE6)
00350   {
00351     /* Set the Master volume */
00352     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MASTER_A_VOL, convertedvol - 0xE7); 
00353     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MASTER_B_VOL, convertedvol - 0xE7);     
00354   }
00355   else
00356   {
00357     /* Set the Master volume */
00358     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MASTER_A_VOL, convertedvol + 0x19); 
00359     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_MASTER_B_VOL, convertedvol + 0x19); 
00360   }
00361 
00362   return counter;
00363 }
00364 
00365 /**
00366   * @brief Sets new frequency.
00367   * @param DeviceAddr: Device address on communication Bus.   
00368   * @param AudioFreq: Audio frequency used to play the audio stream.
00369   * @retval 0 if correct communication, else wrong communication
00370   */
00371 uint32_t cs43l22_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq)
00372 {
00373   return 0;
00374 }
00375 
00376 /**
00377   * @brief Enables or disables the mute feature on the audio codec.
00378   * @param DeviceAddr: Device address on communication Bus.   
00379   * @param Cmd: AUDIO_MUTE_ON to enable the mute or AUDIO_MUTE_OFF to disable the
00380   *             mute mode.
00381   * @retval 0 if correct communication, else wrong communication
00382   */
00383 uint32_t cs43l22_SetMute(uint16_t DeviceAddr, uint32_t Cmd)
00384 {
00385   uint32_t counter = 0;
00386   
00387   /* Set the Mute mode */
00388   if(Cmd == AUDIO_MUTE_ON)
00389   {
00390     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0xFF);
00391     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_HEADPHONE_A_VOL, 0x01);
00392     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_HEADPHONE_B_VOL, 0x01);
00393   }
00394   else /* AUDIO_MUTE_OFF Disable the Mute */
00395   {
00396     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_HEADPHONE_A_VOL, 0x00);
00397     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_HEADPHONE_B_VOL, 0x00);
00398     counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, OutputDev);
00399   }
00400   return counter;
00401 }
00402 
00403 /**
00404   * @brief Switch dynamically (while audio file is played) the output target 
00405   *         (speaker or headphone).
00406   * @note This function modifies a global variable of the audio codec driver: OutputDev.
00407   * @param DeviceAddr: Device address on communication Bus.
00408   * @param Output: specifies the audio output target: OUTPUT_DEVICE_SPEAKER,
00409   *         OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO 
00410   * @retval 0 if correct communication, else wrong communication
00411   */
00412 uint32_t cs43l22_SetOutputMode(uint16_t DeviceAddr, uint8_t Output)
00413 {
00414   uint32_t counter = 0; 
00415   
00416   switch (Output) 
00417   {
00418     case OUTPUT_DEVICE_SPEAKER:
00419       counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0xFA); /* SPK always ON & HP always OFF */
00420       OutputDev = 0xFA;
00421       break;
00422       
00423     case OUTPUT_DEVICE_HEADPHONE:
00424       counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0xAF); /* SPK always OFF & HP always ON */
00425       OutputDev = 0xAF;
00426       break;
00427       
00428     case OUTPUT_DEVICE_BOTH:
00429       counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0xAA); /* SPK always ON & HP always ON */
00430       OutputDev = 0xAA;
00431       break;
00432       
00433     case OUTPUT_DEVICE_AUTO:
00434       counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0x05); /* Detect the HP or the SPK automatically */
00435       OutputDev = 0x05;
00436       break;    
00437       
00438     default:
00439       counter += CODEC_IO_Write(DeviceAddr, CS43L22_REG_POWER_CTL2, 0x05); /* Detect the HP or the SPK automatically */
00440       OutputDev = 0x05;
00441       break;
00442   }  
00443   return counter;
00444 }
00445 
00446 /**
00447   * @brief Resets cs43l22 registers.
00448   * @param DeviceAddr: Device address on communication Bus. 
00449   * @retval 0 if correct communication, else wrong communication
00450   */
00451 uint32_t cs43l22_Reset(uint16_t DeviceAddr)
00452 {
00453   return 0;
00454 }
00455 
00456 /**
00457   * @brief  Writes/Read a single data.
00458   * @param  Addr: I2C address
00459   * @param  Reg: Reg address 
00460   * @param  Value: Data to be written
00461   * @retval None
00462   */
00463 static uint8_t CODEC_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value)
00464 {
00465   uint32_t result = 0;
00466   
00467   AUDIO_IO_Write(Addr, Reg, Value);
00468   
00469 #ifdef VERIFY_WRITTENDATA
00470   /* Verify that the data has been correctly written */  
00471   result = (AUDIO_IO_Read(Addr, Reg) == Value)? 0:1;
00472 #endif /* VERIFY_WRITTENDATA */
00473   
00474   return result;
00475 }
00476 
00477 /**
00478   * @}
00479   */
00480 
00481 /**
00482   * @}
00483   */
00484 
00485 /**
00486   * @}
00487   */
00488 
00489 /**
00490   * @}
00491   */
00492 
00493 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/