1 /** 2 ****************************************************************************** 3 * @file stm32f4xx_hal_sai_ex.c 4 * @author MCD Application Team 5 * @brief SAI Extension HAL module driver. 6 * This file provides firmware functions to manage the following 7 * functionalities of SAI extension peripheral: 8 * + Extension features functions 9 * 10 ****************************************************************************** 11 * @attention 12 * 13 * Copyright (c) 2017 STMicroelectronics. 14 * All rights reserved. 15 * 16 * This software is licensed under terms that can be found in the LICENSE file 17 * in the root directory of this software component. 18 * If no LICENSE file comes with this software, it is provided AS-IS. 19 * 20 ****************************************************************************** 21 @verbatim 22 ============================================================================== 23 ##### SAI peripheral extension features ##### 24 ============================================================================== 25 26 [..] Comparing to other previous devices, the SAI interface for STM32F446xx 27 devices contains the following additional features : 28 29 (+) Possibility to be clocked from PLLR 30 31 ##### How to use this driver ##### 32 ============================================================================== 33 [..] This driver provides functions to manage several sources to clock SAI 34 35 @endverbatim 36 ****************************************************************************** 37 */ 38 39 /* Includes ------------------------------------------------------------------*/ 40 #include "stm32f4xx_hal.h" 41 42 /** @addtogroup STM32F4xx_HAL_Driver 43 * @{ 44 */ 45 46 /** @defgroup SAIEx SAIEx 47 * @brief SAI Extension HAL module driver 48 * @{ 49 */ 50 51 #ifdef HAL_SAI_MODULE_ENABLED 52 53 #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) || \ 54 defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || \ 55 defined(STM32F423xx) 56 57 /* Private typedef -----------------------------------------------------------*/ 58 /* Private define ------------------------------------------------------------*/ 59 /* SAI registers Masks */ 60 /* Private macro -------------------------------------------------------------*/ 61 /* Private variables ---------------------------------------------------------*/ 62 /* Private function prototypes -----------------------------------------------*/ 63 /* Private functions ---------------------------------------------------------*/ 64 65 /** @defgroup SAI_Private_Functions SAI Private Functions 66 * @{ 67 */ 68 /** 69 * @} 70 */ 71 72 /* Exported functions --------------------------------------------------------*/ 73 /** @defgroup SAIEx_Exported_Functions SAI Extended Exported Functions 74 * @{ 75 */ 76 77 /** @defgroup SAIEx_Exported_Functions_Group1 Extension features functions 78 * @brief Extension features functions 79 * 80 @verbatim 81 =============================================================================== 82 ##### Extension features Functions ##### 83 =============================================================================== 84 [..] 85 This subsection provides a set of functions allowing to manage the possible 86 SAI clock sources. 87 88 @endverbatim 89 * @{ 90 */ 91 92 /** 93 * @brief Configure SAI Block synchronization mode 94 * @param hsai pointer to a SAI_HandleTypeDef structure that contains 95 * the configuration information for SAI module. 96 * @retval SAI Clock Input 97 */ SAI_BlockSynchroConfig(SAI_HandleTypeDef * hsai)98void SAI_BlockSynchroConfig(SAI_HandleTypeDef *hsai) 99 { 100 uint32_t tmpregisterGCR; 101 102 #if defined(STM32F446xx) 103 /* This setting must be done with both audio block (A & B) disabled */ 104 switch (hsai->Init.SynchroExt) 105 { 106 case SAI_SYNCEXT_DISABLE : 107 tmpregisterGCR = 0U; 108 break; 109 case SAI_SYNCEXT_OUTBLOCKA_ENABLE : 110 tmpregisterGCR = SAI_GCR_SYNCOUT_0; 111 break; 112 case SAI_SYNCEXT_OUTBLOCKB_ENABLE : 113 tmpregisterGCR = SAI_GCR_SYNCOUT_1; 114 break; 115 default: 116 tmpregisterGCR = 0U; 117 break; 118 } 119 120 if ((hsai->Init.Synchro) == SAI_SYNCHRONOUS_EXT_SAI2) 121 { 122 tmpregisterGCR |= SAI_GCR_SYNCIN_0; 123 } 124 125 if ((hsai->Instance == SAI1_Block_A) || (hsai->Instance == SAI1_Block_B)) 126 { 127 SAI1->GCR = tmpregisterGCR; 128 } 129 else 130 { 131 SAI2->GCR = tmpregisterGCR; 132 } 133 #endif /* STM32F446xx */ 134 #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) || \ 135 defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx) 136 /* This setting must be done with both audio block (A & B) disabled */ 137 switch (hsai->Init.SynchroExt) 138 { 139 case SAI_SYNCEXT_DISABLE : 140 tmpregisterGCR = 0U; 141 break; 142 case SAI_SYNCEXT_OUTBLOCKA_ENABLE : 143 tmpregisterGCR = SAI_GCR_SYNCOUT_0; 144 break; 145 case SAI_SYNCEXT_OUTBLOCKB_ENABLE : 146 tmpregisterGCR = SAI_GCR_SYNCOUT_1; 147 break; 148 default: 149 tmpregisterGCR = 0U; 150 break; 151 } 152 SAI1->GCR = tmpregisterGCR; 153 #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F413xx || STM32F423xx */ 154 } 155 /** 156 * @brief Get SAI Input Clock based on SAI source clock selection 157 * @param hsai pointer to a SAI_HandleTypeDef structure that contains 158 * the configuration information for SAI module. 159 * @retval SAI Clock Input 160 */ SAI_GetInputClock(SAI_HandleTypeDef * hsai)161uint32_t SAI_GetInputClock(SAI_HandleTypeDef *hsai) 162 { 163 /* This variable used to store the SAI_CK_x (value in Hz) */ 164 uint32_t saiclocksource = 0U; 165 166 #if defined(STM32F446xx) 167 if ((hsai->Instance == SAI1_Block_A) || (hsai->Instance == SAI1_Block_B)) 168 { 169 saiclocksource = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SAI1); 170 } 171 else /* SAI2_Block_A || SAI2_Block_B*/ 172 { 173 saiclocksource = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SAI2); 174 } 175 #endif /* STM32F446xx */ 176 #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) || \ 177 defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx) 178 uint32_t vcoinput = 0U, tmpreg = 0U; 179 180 /* Check the SAI Block parameters */ 181 assert_param(IS_SAI_CLK_SOURCE(hsai->Init.ClockSource)); 182 183 /* SAI Block clock source selection */ 184 if (hsai->Instance == SAI1_Block_A) 185 { 186 __HAL_RCC_SAI_BLOCKACLKSOURCE_CONFIG(hsai->Init.ClockSource); 187 } 188 else 189 { 190 __HAL_RCC_SAI_BLOCKBCLKSOURCE_CONFIG((uint32_t)(hsai->Init.ClockSource << 2U)); 191 } 192 193 /* VCO Input Clock value calculation */ 194 if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI) 195 { 196 /* In Case the PLL Source is HSI (Internal Clock) */ 197 vcoinput = (HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM)); 198 } 199 else 200 { 201 /* In Case the PLL Source is HSE (External Clock) */ 202 vcoinput = ((HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM))); 203 } 204 #if defined(STM32F413xx) || defined(STM32F423xx) 205 /* SAI_CLK_x : SAI Block Clock configuration for different clock sources selected */ 206 if (hsai->Init.ClockSource == SAI_CLKSOURCE_PLLR) 207 { 208 /* Configure the PLLI2S division factor */ 209 /* PLL_VCO Input = PLL_SOURCE/PLLM */ 210 /* PLL_VCO Output = PLL_VCO Input * PLLN */ 211 /* SAI_CLK(first level) = PLL_VCO Output/PLLR */ 212 tmpreg = (RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 28U; 213 saiclocksource = (vcoinput * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6U)) / (tmpreg); 214 215 /* SAI_CLK_x = SAI_CLK(first level)/PLLDIVR */ 216 tmpreg = (((RCC->DCKCFGR & RCC_DCKCFGR_PLLDIVR) >> 8U) + 1U); 217 218 saiclocksource = saiclocksource / (tmpreg); 219 220 } 221 else if (hsai->Init.ClockSource == SAI_CLKSOURCE_PLLI2S) 222 { 223 /* Configure the PLLI2S division factor */ 224 /* PLLI2S_VCO Input = PLL_SOURCE/PLLM */ 225 /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */ 226 /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SR */ 227 tmpreg = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28U; 228 saiclocksource = (vcoinput * ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U)) / (tmpreg); 229 230 /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVR */ 231 tmpreg = ((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVR) + 1U); 232 saiclocksource = saiclocksource / (tmpreg); 233 } 234 else if (hsai->Init.ClockSource == SAI_CLKSOURCE_HS) 235 { 236 if ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE) 237 { 238 /* Get the I2S source clock value */ 239 saiclocksource = (uint32_t)(HSE_VALUE); 240 } 241 else 242 { 243 /* Get the I2S source clock value */ 244 saiclocksource = (uint32_t)(HSI_VALUE); 245 } 246 } 247 else /* sConfig->ClockSource == SAI_CLKSource_Ext */ 248 { 249 saiclocksource = EXTERNAL_CLOCK_VALUE; 250 } 251 #else 252 /* SAI_CLK_x : SAI Block Clock configuration for different clock sources selected */ 253 if (hsai->Init.ClockSource == SAI_CLKSOURCE_PLLSAI) 254 { 255 /* Configure the PLLI2S division factor */ 256 /* PLLSAI_VCO Input = PLL_SOURCE/PLLM */ 257 /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */ 258 /* SAI_CLK(first level) = PLLSAI_VCO Output/PLLSAIQ */ 259 tmpreg = (RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> 24U; 260 saiclocksource = (vcoinput * ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIN) >> 6U)) / (tmpreg); 261 262 /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */ 263 tmpreg = (((RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVQ) >> 8U) + 1U); 264 saiclocksource = saiclocksource / (tmpreg); 265 266 } 267 else if (hsai->Init.ClockSource == SAI_CLKSOURCE_PLLI2S) 268 { 269 /* Configure the PLLI2S division factor */ 270 /* PLLI2S_VCO Input = PLL_SOURCE/PLLM */ 271 /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */ 272 /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */ 273 tmpreg = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> 24U; 274 saiclocksource = (vcoinput * ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U)) / (tmpreg); 275 276 /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */ 277 tmpreg = ((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVQ) + 1U); 278 saiclocksource = saiclocksource / (tmpreg); 279 } 280 else /* sConfig->ClockSource == SAI_CLKSource_Ext */ 281 { 282 /* Enable the External Clock selection */ 283 __HAL_RCC_I2S_CONFIG(RCC_I2SCLKSOURCE_EXT); 284 285 saiclocksource = EXTERNAL_CLOCK_VALUE; 286 } 287 #endif /* STM32F413xx || STM32F423xx */ 288 #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F413xx || STM32F423xx */ 289 /* the return result is the value of SAI clock */ 290 return saiclocksource; 291 } 292 293 /** 294 * @} 295 */ 296 297 /** 298 * @} 299 */ 300 301 #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx || STM32F479xx || STM32F413xx || STM32F423xx */ 302 #endif /* HAL_SAI_MODULE_ENABLED */ 303 /** 304 * @} 305 */ 306 307 /** 308 * @} 309 */ 310 311