You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

328 lines
12 KiB

  1. /**
  2. ******************************************************************************
  3. * @file stm32f4xx_hal_sai_ex.c
  4. * @author MCD Application Team
  5. * @version V1.7.1
  6. * @date 14-April-2017
  7. * @brief SAI Extension HAL module driver.
  8. * This file provides firmware functions to manage the following
  9. * functionalities of SAI extension peripheral:
  10. * + Extension features functions
  11. *
  12. @verbatim
  13. ==============================================================================
  14. ##### SAI peripheral extension features #####
  15. ==============================================================================
  16. [..] Comparing to other previous devices, the SAI interface for STM32F446xx
  17. devices contains the following additional features :
  18. (+) Possibility to be clocked from PLLR
  19. ##### How to use this driver #####
  20. ==============================================================================
  21. [..] This driver provides functions to manage several sources to clock SAI
  22. @endverbatim
  23. ******************************************************************************
  24. * @attention
  25. *
  26. * <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
  27. *
  28. * Redistribution and use in source and binary forms, with or without modification,
  29. * are permitted provided that the following conditions are met:
  30. * 1. Redistributions of source code must retain the above copyright notice,
  31. * this list of conditions and the following disclaimer.
  32. * 2. Redistributions in binary form must reproduce the above copyright notice,
  33. * this list of conditions and the following disclaimer in the documentation
  34. * and/or other materials provided with the distribution.
  35. * 3. Neither the name of STMicroelectronics nor the names of its contributors
  36. * may be used to endorse or promote products derived from this software
  37. * without specific prior written permission.
  38. *
  39. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  40. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  41. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  42. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  43. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  44. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  45. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  46. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  47. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  48. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  49. *
  50. ******************************************************************************
  51. */
  52. /* Includes ------------------------------------------------------------------*/
  53. #include "stm32f4xx_hal.h"
  54. /** @addtogroup STM32F4xx_HAL_Driver
  55. * @{
  56. */
  57. /** @defgroup SAIEx SAIEx
  58. * @brief SAI Extension HAL module driver
  59. * @{
  60. */
  61. #ifdef HAL_SAI_MODULE_ENABLED
  62. #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) || \
  63. defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || \
  64. defined(STM32F423xx)
  65. /* Private typedef -----------------------------------------------------------*/
  66. /* Private define ------------------------------------------------------------*/
  67. /* SAI registers Masks */
  68. /* Private macro -------------------------------------------------------------*/
  69. /* Private variables ---------------------------------------------------------*/
  70. /* Private function prototypes -----------------------------------------------*/
  71. /* Private functions ---------------------------------------------------------*/
  72. /** @defgroup SAI_Private_Functions SAI Private Functions
  73. * @{
  74. */
  75. /**
  76. * @}
  77. */
  78. /* Exported functions --------------------------------------------------------*/
  79. /** @defgroup SAIEx_Exported_Functions SAI Extended Exported Functions
  80. * @{
  81. */
  82. /** @defgroup SAIEx_Exported_Functions_Group1 Extension features functions
  83. * @brief Extension features functions
  84. *
  85. @verbatim
  86. ===============================================================================
  87. ##### Extension features Functions #####
  88. ===============================================================================
  89. [..]
  90. This subsection provides a set of functions allowing to manage the possible
  91. SAI clock sources.
  92. @endverbatim
  93. * @{
  94. */
  95. /**
  96. * @brief Configure SAI Block synchronization mode
  97. * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
  98. * the configuration information for SAI module.
  99. * @retval SAI Clock Input
  100. */
  101. void SAI_BlockSynchroConfig(SAI_HandleTypeDef *hsai)
  102. {
  103. uint32_t tmpregisterGCR = 0U;
  104. #if defined(STM32F446xx)
  105. /* This setting must be done with both audio block (A & B) disabled */
  106. switch(hsai->Init.SynchroExt)
  107. {
  108. case SAI_SYNCEXT_DISABLE :
  109. tmpregisterGCR = 0U;
  110. break;
  111. case SAI_SYNCEXT_OUTBLOCKA_ENABLE :
  112. tmpregisterGCR = SAI_GCR_SYNCOUT_0;
  113. break;
  114. case SAI_SYNCEXT_OUTBLOCKB_ENABLE :
  115. tmpregisterGCR = SAI_GCR_SYNCOUT_1;
  116. break;
  117. default:
  118. break;
  119. }
  120. if((hsai->Init.Synchro) == SAI_SYNCHRONOUS_EXT_SAI2)
  121. {
  122. tmpregisterGCR |= SAI_GCR_SYNCIN_0;
  123. }
  124. if((hsai->Instance == SAI1_Block_A) || (hsai->Instance == SAI1_Block_B))
  125. {
  126. SAI1->GCR = tmpregisterGCR;
  127. }
  128. else
  129. {
  130. SAI2->GCR = tmpregisterGCR;
  131. }
  132. #endif /* STM32F446xx */
  133. #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) || \
  134. defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx)
  135. /* This setting must be done with both audio block (A & B) disabled */
  136. switch(hsai->Init.SynchroExt)
  137. {
  138. case SAI_SYNCEXT_DISABLE :
  139. tmpregisterGCR = 0U;
  140. break;
  141. case SAI_SYNCEXT_OUTBLOCKA_ENABLE :
  142. tmpregisterGCR = SAI_GCR_SYNCOUT_0;
  143. break;
  144. case SAI_SYNCEXT_OUTBLOCKB_ENABLE :
  145. tmpregisterGCR = SAI_GCR_SYNCOUT_1;
  146. break;
  147. default:
  148. break;
  149. }
  150. SAI1->GCR = tmpregisterGCR;
  151. #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F413xx || STM32F423xx */
  152. }
  153. /**
  154. * @brief Get SAI Input Clock based on SAI source clock selection
  155. * @param hsai: pointer to a SAI_HandleTypeDef structure that contains
  156. * the configuration information for SAI module.
  157. * @retval SAI Clock Input
  158. */
  159. uint32_t SAI_GetInputClock(SAI_HandleTypeDef *hsai)
  160. {
  161. /* This variable used to store the SAI_CK_x (value in Hz) */
  162. uint32_t saiclocksource = 0U;
  163. #if defined(STM32F446xx)
  164. if ((hsai->Instance == SAI1_Block_A) || (hsai->Instance == SAI1_Block_B))
  165. {
  166. saiclocksource = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SAI1);
  167. }
  168. else /* SAI2_Block_A || SAI2_Block_B*/
  169. {
  170. saiclocksource = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SAI2);
  171. }
  172. #endif /* STM32F446xx */
  173. #if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) || \
  174. defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F413xx) || defined(STM32F423xx)
  175. uint32_t vcoinput = 0U, tmpreg = 0U;
  176. /* Check the SAI Block parameters */
  177. assert_param(IS_SAI_CLK_SOURCE(hsai->Init.ClockSource));
  178. /* SAI Block clock source selection */
  179. if(hsai->Instance == SAI1_Block_A)
  180. {
  181. __HAL_RCC_SAI_BLOCKACLKSOURCE_CONFIG(hsai->Init.ClockSource);
  182. }
  183. else
  184. {
  185. __HAL_RCC_SAI_BLOCKBCLKSOURCE_CONFIG((uint32_t)(hsai->Init.ClockSource << 2U));
  186. }
  187. /* VCO Input Clock value calculation */
  188. if((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSI)
  189. {
  190. /* In Case the PLL Source is HSI (Internal Clock) */
  191. vcoinput = (HSI_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM));
  192. }
  193. else
  194. {
  195. /* In Case the PLL Source is HSE (External Clock) */
  196. vcoinput = ((HSE_VALUE / (uint32_t)(RCC->PLLCFGR & RCC_PLLCFGR_PLLM)));
  197. }
  198. #if defined(STM32F413xx) || defined(STM32F423xx)
  199. /* SAI_CLK_x : SAI Block Clock configuration for different clock sources selected */
  200. if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLR)
  201. {
  202. /* Configure the PLLI2S division factor */
  203. /* PLL_VCO Input = PLL_SOURCE/PLLM */
  204. /* PLL_VCO Output = PLL_VCO Input * PLLN */
  205. /* SAI_CLK(first level) = PLL_VCO Output/PLLR */
  206. tmpreg = (RCC->PLLCFGR & RCC_PLLCFGR_PLLR) >> 28U;
  207. saiclocksource = (vcoinput * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6U))/(tmpreg);
  208. /* SAI_CLK_x = SAI_CLK(first level)/PLLDIVR */
  209. tmpreg = (((RCC->DCKCFGR & RCC_DCKCFGR_PLLDIVR) >> 8U) + 1U);
  210. saiclocksource = saiclocksource/(tmpreg);
  211. }
  212. else if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLI2S)
  213. {
  214. /* Configure the PLLI2S division factor */
  215. /* PLLI2S_VCO Input = PLL_SOURCE/PLLM */
  216. /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
  217. /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SR */
  218. tmpreg = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SR) >> 28U;
  219. saiclocksource = (vcoinput * ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U))/(tmpreg);
  220. /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVR */
  221. tmpreg = ((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVR) + 1U);
  222. saiclocksource = saiclocksource/(tmpreg);
  223. }
  224. else if(hsai->Init.ClockSource == SAI_CLKSOURCE_HS)
  225. {
  226. if((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLSOURCE_HSE)
  227. {
  228. /* Get the I2S source clock value */
  229. saiclocksource = (uint32_t)(HSE_VALUE);
  230. }
  231. else
  232. {
  233. /* Get the I2S source clock value */
  234. saiclocksource = (uint32_t)(HSI_VALUE);
  235. }
  236. }
  237. else /* sConfig->ClockSource == SAI_CLKSource_Ext */
  238. {
  239. saiclocksource = EXTERNAL_CLOCK_VALUE;
  240. }
  241. #else
  242. /* SAI_CLK_x : SAI Block Clock configuration for different clock sources selected */
  243. if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLSAI)
  244. {
  245. /* Configure the PLLI2S division factor */
  246. /* PLLSAI_VCO Input = PLL_SOURCE/PLLM */
  247. /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN */
  248. /* SAI_CLK(first level) = PLLSAI_VCO Output/PLLSAIQ */
  249. tmpreg = (RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIQ) >> 24U;
  250. saiclocksource = (vcoinput * ((RCC->PLLSAICFGR & RCC_PLLSAICFGR_PLLSAIN) >> 6U))/(tmpreg);
  251. /* SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ */
  252. tmpreg = (((RCC->DCKCFGR & RCC_DCKCFGR_PLLSAIDIVQ) >> 8U) + 1U);
  253. saiclocksource = saiclocksource/(tmpreg);
  254. }
  255. else if(hsai->Init.ClockSource == SAI_CLKSOURCE_PLLI2S)
  256. {
  257. /* Configure the PLLI2S division factor */
  258. /* PLLI2S_VCO Input = PLL_SOURCE/PLLM */
  259. /* PLLI2S_VCO Output = PLLI2S_VCO Input * PLLI2SN */
  260. /* SAI_CLK(first level) = PLLI2S_VCO Output/PLLI2SQ */
  261. tmpreg = (RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SQ) >> 24U;
  262. saiclocksource = (vcoinput * ((RCC->PLLI2SCFGR & RCC_PLLI2SCFGR_PLLI2SN) >> 6U))/(tmpreg);
  263. /* SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ */
  264. tmpreg = ((RCC->DCKCFGR & RCC_DCKCFGR_PLLI2SDIVQ) + 1U);
  265. saiclocksource = saiclocksource/(tmpreg);
  266. }
  267. else /* sConfig->ClockSource == SAI_CLKSource_Ext */
  268. {
  269. /* Enable the External Clock selection */
  270. __HAL_RCC_I2S_CONFIG(RCC_I2SCLKSOURCE_EXT);
  271. saiclocksource = EXTERNAL_CLOCK_VALUE;
  272. }
  273. #endif /* STM32F413xx || STM32F423xx */
  274. #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F413xx || STM32F423xx */
  275. /* the return result is the value of SAI clock */
  276. return saiclocksource;
  277. }
  278. /**
  279. * @}
  280. */
  281. /**
  282. * @}
  283. */
  284. #endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx || STM32F479xx || STM32F413xx || STM32F423xx */
  285. #endif /* HAL_SAI_MODULE_ENABLED */
  286. /**
  287. * @}
  288. */
  289. /**
  290. * @}
  291. */
  292. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/