system_SWM341.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /******************************************************************************************************************************************
  2. * 文件名称: system_SWM341.c
  3. * 功能说明: SWM341单片机的时钟设置
  4. * 技术支持: http://www.synwit.com.cn/e/tool/gbook/?bid=1
  5. * 注意事项:
  6. * 版本日期: V1.1.0 2017年10月25日
  7. * 升级记录:
  8. *
  9. *
  10. *******************************************************************************************************************************************
  11. * @attention
  12. *
  13. * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS WITH CODING INFORMATION
  14. * REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. AS A RESULT, SYNWIT SHALL NOT BE HELD LIABLE
  15. * FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
  16. * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONN-
  17. * -ECTION WITH THEIR PRODUCTS.
  18. *
  19. * COPYRIGHT 2012 Synwit Technology
  20. *******************************************************************************************************************************************/
  21. #include <stdint.h>
  22. #include "SWM341.h"
  23. /******************************************************************************************************************************************
  24. * 系统时钟设定
  25. *****************************************************************************************************************************************/
  26. #define SYS_CLK_20MHz 0 //0 内部高频20MHz RC振荡器
  27. #define SYS_CLK_2M5Hz 1 //1 内部高频2.5MHz RC振荡器
  28. #define SYS_CLK_40MHz 2 //2 内部高频40MHz RC振荡器
  29. #define SYS_CLK_5MHz 3 //3 内部高频 5MHz RC振荡器
  30. #define SYS_CLK_XTAL 4 //4 外部晶体振荡器(4-32MHz)
  31. #define SYS_CLK_XTAL_DIV8 5 //5 外部晶体振荡器(4-32MHz) 8分频
  32. #define SYS_CLK_PLL 6 //6 锁相环输出
  33. #define SYS_CLK_PLL_DIV8 7 //7 锁相环输出 8分频
  34. #define SYS_CLK_32KHz 8 //8 内部低频32KHz RC 振荡器
  35. #define SYS_CLK_XTAL_32K 9 //9 外部低频32KHz 晶体振荡器
  36. #define SYS_CLK SYS_CLK_PLL
  37. #define __HSI (20000000UL) //高速内部时钟
  38. #define __LSI ( 32000UL) //低速内部时钟
  39. #define __HSE (12000000UL) //高速外部时钟
  40. #define __LSE ( 32768UL) //低速外部时钟
  41. /********************************** PLL 设定 **********************************************
  42. * VCO输出频率 = PLL输入时钟 / INDIV * 4 * FBDIV
  43. * PLL输出频率 = PLL输入时钟 / INDIV * 4 * FBDIV / OUTDIV = VCO输出频率 / OUTDIV
  44. * 注意:VCO输出频率需要在 [600MHz, 1400MHz] 之间
  45. *****************************************************************************************/
  46. #define SYS_PLL_SRC SYS_CLK_XTAL //可取值SYS_CLK_20MHz、SYS_CLK_XTAL
  47. #define PLL_IN_DIV 3
  48. #define PLL_FB_DIV 75
  49. #define PLL_OUT_DIV8 0
  50. #define PLL_OUT_DIV4 1
  51. #define PLL_OUT_DIV2 2
  52. #define PLL_OUT_DIV PLL_OUT_DIV8
  53. uint32_t SystemCoreClock = __HSI; //System Clock Frequency (Core Clock)
  54. uint32_t CyclesPerUs = (__HSI / 1000000); //Cycles per micro second
  55. /******************************************************************************************************************************************
  56. * 函数名称:
  57. * 功能说明: This function is used to update the variable SystemCoreClock and must be called whenever the core clock is changed
  58. * 输 入:
  59. * 输 出:
  60. * 注意事项:
  61. ******************************************************************************************************************************************/
  62. void SystemCoreClockUpdate(void)
  63. {
  64. if(SYS->CLKSEL & SYS_CLKSEL_SYS_Msk) //SYS <= HRC
  65. {
  66. if(SYS->HRCCR & SYS_HRCCR_DBL_Msk) //HRC = 40MHz
  67. {
  68. SystemCoreClock = __HSI*2;
  69. }
  70. else //HRC = 20MHz
  71. {
  72. SystemCoreClock = __HSI;
  73. }
  74. }
  75. else //SYS <= CLK
  76. {
  77. switch((SYS->CLKSEL & SYS_CLKSEL_CLK_Msk) >> SYS_CLKSEL_CLK_Pos)
  78. {
  79. case 0:
  80. SystemCoreClock = __LSI;
  81. break;
  82. case 1:
  83. if(SYS->PLLCR & SYS_PLLCR_INSEL_Msk) //PLL_IN <= HRC
  84. {
  85. SystemCoreClock = __HSI;
  86. }
  87. else //PLL_IN <= XTAL
  88. {
  89. SystemCoreClock = __HSE;
  90. }
  91. SystemCoreClock = SystemCoreClock / PLL_IN_DIV * PLL_FB_DIV * 4 / (2 << (2 - PLL_OUT_DIV));
  92. break;
  93. case 2:
  94. SystemCoreClock = __LSE;
  95. break;
  96. case 3:
  97. SystemCoreClock = __HSE;
  98. break;
  99. case 4:
  100. SystemCoreClock = __HSI;
  101. if(SYS->HRCCR & SYS_HRCCR_DBL_Msk) SystemCoreClock *= 2;
  102. break;
  103. }
  104. if(SYS->CLKSEL & SYS_CLKSEL_CLK_DIVx_Msk) SystemCoreClock /= 8;
  105. }
  106. CyclesPerUs = SystemCoreClock / 1000000;
  107. }
  108. /******************************************************************************************************************************************
  109. * 函数名称:
  110. * 功能说明: The necessary initializaiton of systerm
  111. * 输 入:
  112. * 输 出:
  113. * 注意事项:
  114. ******************************************************************************************************************************************/
  115. void SystemInit(void)
  116. {
  117. SYS->CLKEN0 |= (1 << SYS_CLKEN0_ANAC_Pos);
  118. Flash_Param_at_xMHz(150);
  119. switch(SYS_CLK)
  120. {
  121. case SYS_CLK_20MHz:
  122. switchTo20MHz();
  123. break;
  124. case SYS_CLK_2M5Hz:
  125. switchTo2M5Hz();
  126. break;
  127. case SYS_CLK_40MHz:
  128. switchTo40MHz();
  129. break;
  130. case SYS_CLK_5MHz:
  131. switchTo5MHz();
  132. break;
  133. case SYS_CLK_XTAL:
  134. switchToXTAL(0);
  135. break;
  136. case SYS_CLK_XTAL_DIV8:
  137. switchToXTAL(1);
  138. break;
  139. case SYS_CLK_PLL:
  140. switchToPLL(0);
  141. break;
  142. case SYS_CLK_PLL_DIV8:
  143. switchToPLL(1);
  144. break;
  145. case SYS_CLK_32KHz:
  146. switchTo32KHz();
  147. break;
  148. case SYS_CLK_XTAL_32K:
  149. switchToXTAL_32K();
  150. break;
  151. }
  152. SystemCoreClockUpdate();
  153. if(SystemCoreClock > 120000000)
  154. {
  155. Flash_Param_at_xMHz(150);
  156. }
  157. else if(SystemCoreClock > 80000000)
  158. {
  159. Flash_Param_at_xMHz(120);
  160. }
  161. else if(SystemCoreClock > 40000000)
  162. {
  163. Flash_Param_at_xMHz(80);
  164. }
  165. else if(SystemCoreClock > 30000000)
  166. {
  167. Flash_Param_at_xMHz(40);
  168. }
  169. else
  170. {
  171. Flash_Param_at_xMHz(30);
  172. }
  173. PORTM->PULLD &= ~(1 << PIN1);
  174. PORTM->PULLU &= ~((1 << PIN2) | (1 << PIN3));
  175. SYS->USBPHYCR &= ~SYS_USBPHYCR_OPMODE_Msk;
  176. SYS->USBPHYCR |= (1 << SYS_USBPHYCR_OPMODE_Pos); //Non-Driving, DP Pull-Up disable
  177. }
  178. void FPU_Enable(void)
  179. {
  180. #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
  181. SCB->CPACR |= (0xF << 20);
  182. #endif
  183. }
  184. static void delay_3ms(void)
  185. {
  186. uint32_t i;
  187. if(((SYS->CLKSEL & SYS_CLKSEL_SYS_Msk) == 0) &&
  188. ((((SYS->CLKSEL & SYS_CLKSEL_CLK_Msk) >> SYS_CLKSEL_CLK_Pos) == 0) || //LSI 32KHz
  189. (((SYS->CLKSEL & SYS_CLKSEL_CLK_Msk) >> SYS_CLKSEL_CLK_Pos) == 2))) //LSE 32KHz
  190. {
  191. for(i = 0; i < 20; i++) __NOP();
  192. }
  193. else
  194. {
  195. for(i = 0; i < 20000; i++) __NOP();
  196. }
  197. }
  198. void switchTo20MHz(void)
  199. {
  200. SYS->HRCCR = (1 << SYS_HRCCR_ON_Pos) |
  201. (0 << SYS_HRCCR_DBL_Pos); //HRC = 20Hz
  202. delay_3ms();
  203. SYS->CLKSEL |= (1 << SYS_CLKSEL_SYS_Pos); //SYS <= HRC
  204. }
  205. void switchTo2M5Hz(void)
  206. {
  207. switchTo20MHz();
  208. SYS->CLKDIVx_ON = 1;
  209. SYS->CLKSEL &= ~SYS_CLKSEL_CLK_Msk;
  210. SYS->CLKSEL |= (4 << SYS_CLKSEL_CLK_Pos); //CLK <= HRC
  211. SYS->CLKSEL |= (1 << SYS_CLKSEL_CLK_DIVx_Pos);
  212. delay_3ms();
  213. SYS->CLKSEL &=~(1 << SYS_CLKSEL_SYS_Pos); //SYS <= HRC/8
  214. }
  215. void switchTo40MHz(void)
  216. {
  217. SYS->HRCCR = (1 << SYS_HRCCR_ON_Pos) |
  218. (1 << SYS_HRCCR_DBL_Pos); //HRC = 40MHz
  219. delay_3ms();
  220. SYS->CLKSEL |= (1 << SYS_CLKSEL_SYS_Pos); //SYS <= HRC
  221. }
  222. void switchTo5MHz(void)
  223. {
  224. switchTo40MHz();
  225. SYS->CLKDIVx_ON = 1;
  226. SYS->CLKSEL &= ~SYS_CLKSEL_CLK_Msk;
  227. SYS->CLKSEL |= (4 << SYS_CLKSEL_CLK_Pos); //CLK <= HRC
  228. SYS->CLKSEL |= (1 << SYS_CLKSEL_CLK_DIVx_Pos);
  229. delay_3ms();
  230. SYS->CLKSEL &=~(1 << SYS_CLKSEL_SYS_Pos); //SYS <= HRC/8
  231. }
  232. void switchToXTAL(uint32_t div8)
  233. {
  234. switchTo20MHz();
  235. PORT_Init(PORTA, PIN3, PORTA_PIN3_XTAL_IN, 0);
  236. PORT_Init(PORTA, PIN4, PORTA_PIN4_XTAL_OUT, 0);
  237. SYS->XTALCR |= (1 << SYS_XTALCR_ON_Pos) | (15 << SYS_XTALCR_DRV_Pos) | (1 << SYS_XTALCR_DET_Pos);
  238. delay_3ms();
  239. delay_3ms();
  240. SYS->CLKDIVx_ON = 1;
  241. SYS->CLKSEL &= ~SYS_CLKSEL_CLK_Msk;
  242. SYS->CLKSEL |= (3 << SYS_CLKSEL_CLK_Pos); //CLK <= XTAL
  243. if(div8) SYS->CLKSEL |= (1 << SYS_CLKSEL_CLK_DIVx_Pos);
  244. else SYS->CLKSEL &=~(1 << SYS_CLKSEL_CLK_DIVx_Pos);
  245. SYS->CLKSEL &=~(1 << SYS_CLKSEL_SYS_Pos); //SYS <= XTAL
  246. }
  247. void switchToPLL(uint32_t div8)
  248. {
  249. switchTo20MHz();
  250. PLLInit();
  251. SYS->CLKDIVx_ON = 1;
  252. SYS->CLKSEL &= ~SYS_CLKSEL_CLK_Msk;
  253. SYS->CLKSEL |= (1 << SYS_CLKSEL_CLK_Pos); //CLK <= PLL
  254. if(div8) SYS->CLKSEL |= (1 << SYS_CLKSEL_CLK_DIVx_Pos);
  255. else SYS->CLKSEL &=~(1 << SYS_CLKSEL_CLK_DIVx_Pos);
  256. SYS->CLKSEL &=~(1 << SYS_CLKSEL_SYS_Pos); //SYS <= PLL
  257. }
  258. void switchTo32KHz(void)
  259. {
  260. switchTo20MHz();
  261. SYS->LRCCR = (1 << SYS_LRCCR_ON_Pos);
  262. SYS->CLKDIVx_ON = 1;
  263. SYS->CLKSEL &= ~SYS_CLKSEL_CLK_Msk;
  264. SYS->CLKSEL |= (0 << SYS_CLKSEL_CLK_Pos); //CLK <= LRC
  265. SYS->CLKSEL &=~(1 << SYS_CLKSEL_CLK_DIVx_Pos);
  266. delay_3ms();
  267. SYS->CLKSEL &=~(1 << SYS_CLKSEL_SYS_Pos); //SYS <= LRC
  268. }
  269. void switchToXTAL_32K(void)
  270. {
  271. uint32_t i;
  272. switchTo20MHz();
  273. SYS->XTALCR |= (1 << SYS_XTALCR_32KON_Pos) | (7 << SYS_XTALCR_32KDRV_Pos) | (1 << SYS_XTALCR_32KDET_Pos);
  274. for(i = 0; i < 1000; i++) __NOP();
  275. SYS->CLKDIVx_ON = 1;
  276. SYS->CLKSEL &= ~SYS_CLKSEL_CLK_Msk;
  277. SYS->CLKSEL |= (2 << SYS_CLKSEL_CLK_Pos); //CLK <= XTAL_32K
  278. SYS->CLKSEL &=~(1 << SYS_CLKSEL_CLK_DIVx_Pos);
  279. delay_3ms();
  280. SYS->CLKSEL &=~(1 << SYS_CLKSEL_SYS_Pos); //SYS <= XTAL_32K
  281. }
  282. void PLLInit(void)
  283. {
  284. if(SYS_PLL_SRC == SYS_CLK_20MHz)
  285. {
  286. SYS->HRCCR = (1 << SYS_HRCCR_ON_Pos) |
  287. (0 << SYS_HRCCR_DBL_Pos); //HRC = 20Hz
  288. delay_3ms();
  289. SYS->PLLCR |= (1 << SYS_PLLCR_INSEL_Pos); //PLL_SRC <= HRC
  290. }
  291. else if(SYS_PLL_SRC == SYS_CLK_XTAL)
  292. {
  293. PORT_Init(PORTA, PIN3, PORTA_PIN3_XTAL_IN, 0);
  294. PORT_Init(PORTA, PIN4, PORTA_PIN4_XTAL_OUT, 0);
  295. SYS->XTALCR |= (1 << SYS_XTALCR_ON_Pos) | (15 << SYS_XTALCR_DRV_Pos) | (1 << SYS_XTALCR_DET_Pos);
  296. delay_3ms();
  297. delay_3ms();
  298. SYS->PLLCR &= ~(1 << SYS_PLLCR_INSEL_Pos); //PLL_SRC <= XTAL
  299. }
  300. SYS->PLLDIV &= ~(SYS_PLLDIV_INDIV_Msk |
  301. SYS_PLLDIV_FBDIV_Msk |
  302. SYS_PLLDIV_OUTDIV_Msk);
  303. SYS->PLLDIV |= (PLL_IN_DIV << SYS_PLLDIV_INDIV_Pos) |
  304. (PLL_FB_DIV << SYS_PLLDIV_FBDIV_Pos) |
  305. (PLL_OUT_DIV<< SYS_PLLDIV_OUTDIV_Pos);
  306. SYS->PLLCR &= ~(1 << SYS_PLLCR_OFF_Pos);
  307. while(SYS->PLLLOCK == 0); //等待PLL锁定
  308. SYS->PLLCR |= (1 << SYS_PLLCR_OUTEN_Pos);
  309. }