STM32F439xx HAL User Manual
stm32f4xx_hal_sai_ex.c
Go to the documentation of this file.
00001 /**
00002   ******************************************************************************
00003   * @file    stm32f4xx_hal_sai_ex.c
00004   * @author  MCD Application Team
00005   * @brief   SAI Extension HAL module driver.
00006   *          This file provides firmware functions to manage the following 
00007   *          functionalities of SAI extension peripheral:
00008   *           + Extension features functions
00009   *         
00010   @verbatim
00011   ==============================================================================
00012                ##### SAI peripheral extension features  #####
00013   ==============================================================================
00014            
00015   [..] Comparing to other previous devices, the SAI interface for STM32F446xx 
00016        devices contains the following additional features :
00017        
00018        (+) Possibility to be clocked from PLLR
00019    
00020                      ##### How to use this driver #####
00021   ==============================================================================
00022   [..] This driver provides functions to manage several sources to clock SAI
00023   
00024   @endverbatim
00025   ******************************************************************************
00026   * @attention
00027   *
00028   * <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
00029   *
00030   * Redistribution and use in source and binary forms, with or without modification,
00031   * are permitted provided that the following conditions are met:
00032   *   1. Redistributions of source code must retain the above copyright notice,
00033   *      this list of conditions and the following disclaimer.
00034   *   2. Redistributions in binary form must reproduce the above copyright notice,
00035   *      this list of conditions and the following disclaimer in the documentation
00036   *      and/or other materials provided with the distribution.
00037   *   3. Neither the name of STMicroelectronics nor the names of its contributors
00038   *      may be used to endorse or promote products derived from this software
00039   *      without specific prior written permission.
00040   *
00041   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00042   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00043   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00044   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00045   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00046   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00047   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00048   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00049   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00050   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00051   *
00052   ******************************************************************************
00053   */ 
00054 
00055 /* Includes ------------------------------------------------------------------*/
00056 #include "stm32f4xx_hal.h"
00057 
00058 /** @addtogroup STM32F4xx_HAL_Driver
00059   * @{
00060   */
00061 
00062 /** @defgroup SAIEx SAIEx
00063   * @brief SAI Extension HAL module driver
00064   * @{
00065   */
00066 
00067 #ifdef HAL_SAI_MODULE_ENABLED
00068 
00069 #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) || \
00070     defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || \
00071     defined(STM32F423xx)
00072 
00073 /* Private typedef -----------------------------------------------------------*/
00074 /* Private define ------------------------------------------------------------*/
00075 /* SAI registers Masks */
00076 /* Private macro -------------------------------------------------------------*/
00077 /* Private variables ---------------------------------------------------------*/
00078 /* Private function prototypes -----------------------------------------------*/
00079 /* Private functions ---------------------------------------------------------*/
00080 
00081 /** @defgroup SAI_Private_Functions  SAI Private Functions
00082   * @{
00083   */
00084  /**
00085   * @}
00086   */
00087   
00088 /* Exported functions --------------------------------------------------------*/
00089 /** @defgroup SAIEx_Exported_Functions SAI Extended Exported Functions
00090   * @{
00091   */
00092 
00093 /** @defgroup SAIEx_Exported_Functions_Group1 Extension features functions 
00094   *  @brief   Extension features functions
00095   *
00096 @verbatim    
00097  ===============================================================================
00098                        ##### Extension features Functions #####
00099  ===============================================================================
00100     [..]
00101     This subsection provides a set of functions allowing to manage the possible 
00102     SAI clock sources.
00103 
00104 @endverbatim
00105   * @{
00106   */
00107 
00108 /**
00109   * @brief  Configure SAI Block synchronization mode
00110   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
00111   *               the configuration information for SAI module.   
00112   * @retval SAI Clock Input 
00113   */
00114 void SAI_BlockSynchroConfig(SAI_HandleTypeDef *hsai)
00115 {
00116   uint32_t tmpregisterGCR = 0U;
00117 
00118 #if defined(STM32F446xx)  
00119   /* This setting must be done with both audio block (A & B) disabled         */
00120   switch(hsai->Init.SynchroExt)
00121   {
00122   case SAI_SYNCEXT_DISABLE :
00123     tmpregisterGCR = 0U;
00124     break;
00125   case SAI_SYNCEXT_OUTBLOCKA_ENABLE :
00126     tmpregisterGCR = SAI_GCR_SYNCOUT_0;
00127     break;
00128   case SAI_SYNCEXT_OUTBLOCKB_ENABLE :
00129     tmpregisterGCR = SAI_GCR_SYNCOUT_1;
00130     break;
00131   default:
00132     break;
00133   }
00134 
00135   if((hsai->Init.Synchro) == SAI_SYNCHRONOUS_EXT_SAI2)
00136   {
00137     tmpregisterGCR |= SAI_GCR_SYNCIN_0;
00138   }
00139 
00140   if((hsai->Instance == SAI1_Block_A) || (hsai->Instance == SAI1_Block_B))
00141   {
00142     SAI1->GCR = tmpregisterGCR;
00143   }
00144   else 
00145   {
00146     SAI2->GCR = tmpregisterGCR;
00147   }
00148 #endif /* STM32F446xx */
00149 #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) || \
00150     defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx)
00151   /* This setting must be done with both audio block (A & B) disabled         */
00152   switch(hsai->Init.SynchroExt)
00153   {
00154   case SAI_SYNCEXT_DISABLE :
00155     tmpregisterGCR = 0U;
00156     break;
00157   case SAI_SYNCEXT_OUTBLOCKA_ENABLE :
00158     tmpregisterGCR = SAI_GCR_SYNCOUT_0;
00159     break;
00160   case SAI_SYNCEXT_OUTBLOCKB_ENABLE :
00161     tmpregisterGCR = SAI_GCR_SYNCOUT_1;
00162     break;
00163   default:
00164     break;
00165   }
00166   SAI1->GCR = tmpregisterGCR;
00167 #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F413xx || STM32F423xx */ 
00168 }
00169   /**
00170   * @brief  Get SAI Input Clock based on SAI source clock selection
00171   * @param  hsai pointer to a SAI_HandleTypeDef structure that contains
00172   *               the configuration information for SAI module.   
00173   * @retval SAI Clock Input 
00174   */
00175 uint32_t SAI_GetInputClock(SAI_HandleTypeDef *hsai)   
00176 {
00177   /* This variable used to store the SAI_CK_x (value in Hz) */
00178   uint32_t saiclocksource = 0U;
00179   
00180 #if defined(STM32F446xx)
00181   if ((hsai->Instance == SAI1_Block_A) || (hsai->Instance == SAI1_Block_B))
00182   {
00183     saiclocksource = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SAI1);
00184   }
00185   else /* SAI2_Block_A || SAI2_Block_B*/
00186   {
00187     saiclocksource = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SAI2); 
00188   }
00189 #endif /* STM32F446xx */
00190 #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) || \
00191   defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx)
00192   uint32_t vcoinput = 0U, tmpreg = 0U;
00193   
00194   /* Check the SAI Block parameters */
00195   assert_param(IS_SAI_CLK_SOURCE(hsai->Init.ClockSource));
00196  
00197   /* SAI Block clock source selection */
00198   if(hsai->Instance == SAI1_Block_A)
00199   {
00200     __HAL_RCC_SAI_BLOCKACLKSOURCE_CONFIG(hsai->Init.ClockSource);
00201   }
00202   else
00203   {
00204     __HAL_RCC_SAI_BLOCKBCLKSOURCE_CONFIG((uint32_t)(hsai->Init.ClockSource << 2U));
00205   }
00206   
00207   /* VCO Input Clock value calculation */
00208   if((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI)
00209   {
00210     /* In Case the PLL Source is HSI (Internal Clock) */
00211     vcoinput = (HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
00212   }
00213   else
00214   {
00215     /* In Case the PLL Source is HSE (External Clock) */
00216     vcoinput = ((HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM)));
00217   }
00218 #if defined(STM32F413xx) || defined(STM32F423xx)
00219  /* SAI_CLK_x : SAI Block Clock configuration for different clock sources selected */
00220   if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLR)
00221   {
00222     /* Configure the PLLI2S division factor */
00223     /* PLL_VCO Input  = PLL_SOURCE/PLLM */
00224     /* PLL_VCO Output = PLL_VCO Input * PLLN */
00225     /* SAI_CLK(first level) = PLL_VCO Output/PLLR */
00226     tmpreg = (RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 28U;
00227     saiclocksource = (vcoinput * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6U))/(tmpreg);
00228 
00229     /* SAI_CLK_x = SAI_CLK(first level)/PLLDIVR */
00230     tmpreg = (((RCC->DCKCFGR & RCC_DCKCFGR_PLLDIVR) >> 8U) + 1U);
00231       
00232     saiclocksource = saiclocksource/(tmpreg); 
00233 
00234   }
00235   else if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLI2S)
00236   {        
00237     /* Configure the PLLI2S division factor */
00238     /* PLLI2S_VCO Input  = PLL_SOURCE/PLLM */
00239     /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
00240     /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SR */
00241     tmpreg = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28U;
00242     saiclocksource = (vcoinput * ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U))/(tmpreg);
00243     
00244     /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVR */
00245     tmpreg = ((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVR) + 1U); 
00246     saiclocksource = saiclocksource/(tmpreg);
00247   }
00248   else if(hsai->Init.ClockSource == SAI_CLKSOURCE_HS)
00249   {
00250     if((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE)
00251     {
00252       /* Get the I2S source clock value */
00253       saiclocksource = (uint32_t)(HSE_VALUE);
00254     }
00255     else
00256     {
00257       /* Get the I2S source clock value */
00258       saiclocksource = (uint32_t)(HSI_VALUE);
00259     }
00260   }
00261   else /* sConfig->ClockSource == SAI_CLKSource_Ext */
00262   {
00263     saiclocksource = EXTERNAL_CLOCK_VALUE;
00264   }
00265 #else
00266   /* SAI_CLK_x : SAI Block Clock configuration for different clock sources selected */
00267   if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLSAI)
00268   {
00269     /* Configure the PLLI2S division factor */
00270     /* PLLSAI_VCO Input  = PLL_SOURCE/PLLM */
00271     /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
00272     /* SAI_CLK(first level) = PLLSAI_VCO Output/PLLSAIQ */
00273     tmpreg = (RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> 24U;
00274     saiclocksource = (vcoinput * ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIN) >> 6U))/(tmpreg);
00275 
00276     /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */
00277     tmpreg = (((RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVQ) >> 8U) + 1U);
00278     saiclocksource = saiclocksource/(tmpreg); 
00279 
00280   }
00281   else if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLI2S)
00282   {        
00283     /* Configure the PLLI2S division factor */
00284     /* PLLI2S_VCO Input  = PLL_SOURCE/PLLM */
00285     /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
00286     /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */
00287     tmpreg = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> 24U;
00288     saiclocksource = (vcoinput * ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U))/(tmpreg);
00289     
00290     /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */
00291     tmpreg = ((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVQ) + 1U); 
00292     saiclocksource = saiclocksource/(tmpreg);
00293   }
00294   else /* sConfig->ClockSource == SAI_CLKSource_Ext */
00295   {
00296     /* Enable the External Clock selection */
00297     __HAL_RCC_I2S_CONFIG(RCC_I2SCLKSOURCE_EXT);
00298     
00299     saiclocksource = EXTERNAL_CLOCK_VALUE;
00300   }
00301 #endif /* STM32F413xx || STM32F423xx */  
00302 #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F413xx || STM32F423xx */
00303        /* the return result is the value of SAI clock */
00304   return saiclocksource;
00305 }
00306 
00307 /**
00308   * @}
00309   */
00310 
00311 /**
00312   * @}
00313   */
00314 
00315 #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx  || STM32F446xx || STM32F469xx || STM32F479xx || STM32F413xx || STM32F423xx */
00316 #endif /* HAL_SAI_MODULE_ENABLED */
00317 /**
00318   * @}
00319   */
00320 
00321 /**
00322   * @}
00323   */
00324 
00325 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/