system.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. #include "system.h"
  2. #include "uart.h"
  3. #include "flash.h"
  4. SYS_ClocksTypeDef SYS_Clocks = {
  5. .HSI_FREQUENCY = BOARD_HSI_FREQUENCY,
  6. .HSE_FREQUENCY = BOARD_HSE_FREQUENCY,
  7. .PLL_FREQUENCY = BOARD_PLL_FREQUENCY,
  8. .EXT_FREQUENCY = BOARD_EXT_FREQUENCY,
  9. };
  10. uint32_t SYS_GetSysClkFreq(void)
  11. {
  12. switch (SYS->CLK_CNTL & SYS_CLK_SOURCE_MASK) {
  13. case SYS_CLK_SOURCE_HSI:
  14. return SYS_Clocks.HSI_FREQUENCY;
  15. case SYS_CLK_SOURCE_HSE:
  16. return SYS_Clocks.HSE_FREQUENCY;
  17. case SYS_CLK_SOURCE_PLL:
  18. return SYS_Clocks.PLL_FREQUENCY;
  19. default:
  20. return SYS_Clocks.EXT_FREQUENCY;
  21. }
  22. }
  23. uint32_t SYS_GetPclkFreq(void)
  24. {
  25. return SYS_GetSysClkFreq() / (SYS->PBUS_DIVIDER + 1);
  26. }
  27. void SYS_SwitchHSIClock(void)
  28. {
  29. SYS->CLK_CNTL &= ~SYS_CLK_SOURCE_MASK;
  30. SYS->CLK_CNTL &= ~(SYS_CLK_PLL_ON | SYS_CLK_HSE_ON); // Turn off HSE and PLL, must be done after clock source switched to HSI
  31. }
  32. void SYS_SwitchHSEClock(SYS_HSE_BypassTypeDef hse_bypass)
  33. {
  34. SYS_SwitchHSIClock();
  35. uint32_t clk_control = SYS->CLK_CNTL;
  36. // Turn on HSE clock
  37. clk_control |= SYS_CLK_HSE_ON;
  38. if (hse_bypass == SYS_HSE_BYPASS_ON) {
  39. clk_control |= SYS_CLK_HSE_BYP;
  40. } else {
  41. clk_control &= ~SYS_CLK_HSE_BYP;
  42. }
  43. SYS->CLK_CNTL = clk_control;
  44. // Wait for HSE ready and switch
  45. while (!SYS_IsHseReady());
  46. clk_control |= SYS_CLK_SOURCE_HSE;
  47. SYS->CLK_CNTL = clk_control;
  48. }
  49. void SYS_SwitchPLLClock(SYS_HSE_BypassTypeDef hse_bypass)
  50. {
  51. SYS_SwitchHSIClock();
  52. SYS_SetSclkAuto(SYS_GetPLLFreq()); // Since PLL frequency may exceed FLASH_MAX_FREQ
  53. uint32_t clk_control = SYS->CLK_CNTL;
  54. // Turn on PLL clock
  55. clk_control &= ~SYS_CLK_HSE_BYP;
  56. switch (hse_bypass) {
  57. case SYS_HSE_BYPASS_ON:
  58. clk_control |= SYS_CLK_HSE_BYP;
  59. // Fall through
  60. case SYS_HSE_BYPASS_OFF:
  61. clk_control |= SYS_CLK_HSE_ON;
  62. // Fall through
  63. default:
  64. clk_control |= SYS_CLK_PLL_ON;
  65. break;
  66. }
  67. SYS->CLK_CNTL = clk_control;
  68. if (clk_control & SYS_CLK_HSE_ON) {
  69. while (!SYS_IsHseReady());
  70. }
  71. uint32_t counter = 0;
  72. // Wait for PLL ready and switch
  73. while (!SYS_IsPllReady()) {
  74. if (++counter > 5000) {
  75. counter = 0;
  76. SYS->CLK_CNTL = clk_control & ~SYS_CLK_PLL_ON;
  77. SYS->CLK_CNTL = clk_control;
  78. }
  79. }
  80. clk_control |= SYS_CLK_SOURCE_PLL;
  81. SYS->CLK_CNTL = clk_control;
  82. }
  83. void SYS_SetSclkDivider(uint8_t divider)
  84. {
  85. MODIFY_BIT(SYS->CLK_CNTL, SYS_SCLK_DIV_HIGH_MASK | SYS_SCLK_DIV_LOW_MASK, SYS_SCLK_DIV_HIGH(divider) | SYS_SCLK_DIV_LOW(divider));
  86. }
  87. uint8_t SYS_SetSclkAuto(uint32_t freq)
  88. {
  89. uint8_t divider = (freq - 1) / FLASH_MAX_FREQ;
  90. SYS_SetSclkDivider(divider);
  91. return divider;
  92. }
  93. void SYS_EnterSleepMode(void)
  94. {
  95. MODIFY_BIT(SYS->PWR_CNTL, SYS_LOWPOWER_MODE_MASK, SYS_SLEEP_MODE);
  96. asm("fence"); // Make sure SYS->PWR_CNTL is effective
  97. SYS_EnterLowPower();
  98. }
  99. void SYS_EnterStopMode(void)
  100. {
  101. MODIFY_BIT(SYS->PWR_CNTL, SYS_LOWPOWER_MODE_MASK, SYS_STOP_MODE);
  102. asm("fence"); // Make sure SYS->PWR_CNTL is effective
  103. SYS_SwitchHSIClock();
  104. SYS_EnterLowPower();
  105. }
  106. void SYS_EnterStandbyMode(void)
  107. {
  108. MODIFY_BIT(SYS->PWR_CNTL, SYS_LOWPOWER_MODE_MASK, SYS_STANDBY_MODE);
  109. asm("fence"); // Make sure SYS->PWR_CNTL is effective
  110. SYS_SwitchHSIClock();
  111. SYS_EnterLowPower();
  112. }