Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 

312 рядки
10 KiB

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