Advertisement
dylanweber

RCC header file

Mar 19th, 2023
143
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.76 KB | Source Code | 0 0
  1. #include "GPIO.hpp"
  2.  
  3. #include <cmath>
  4. #include <cstddef>
  5. #include <cstdint>
  6. #include <tuple>
  7. #include <type_traits>
  8.  
  9. #pragma once
  10.  
  11. using reg32_t = volatile uint32_t;
  12.  
  13. /**
  14.  * @brief Reset and clock control registers class
  15.  *
  16.  */
  17. class RCC {
  18.   private:
  19.     union {
  20.         reg32_t reg;
  21.         struct {
  22.             reg32_t : 4;
  23.             reg32_t PLLI2SRDY : 1;
  24.             reg32_t PLLI2SON : 1;
  25.             reg32_t PLLRDY : 1;
  26.             reg32_t PLLON : 1;
  27.             reg32_t : 4;
  28.             reg32_t CSSON : 1;
  29.             reg32_t HSEBYP : 1;
  30.             reg32_t HSERDY : 1;
  31.             reg32_t HSEON : 1;
  32.             reg32_t HSICAL : 8;
  33.             reg32_t HSITRIM : 5;
  34.             reg32_t : 1;
  35.             reg32_t HSIRDY : 1;
  36.             reg32_t HSION : 1;
  37.         } bits;
  38.     } CR;
  39.     union {
  40.         reg32_t reg;
  41.         struct {
  42.             reg32_t : 4;
  43.             reg32_t PLLQ : 4;
  44.             reg32_t : 1;
  45.             reg32_t PLLSRC : 1;
  46.             reg32_t : 4;
  47.             reg32_t PLLP : 2;
  48.             reg32_t : 1;
  49.             reg32_t PLLN : 9;
  50.             reg32_t PLLM : 6;
  51.         } bits;
  52.     } PLLCFGR;
  53.     union {
  54.         reg32_t reg;
  55.         struct {
  56.             reg32_t MCO2 : 2;
  57.             reg32_t MCO2PRE : 3;
  58.             reg32_t MCO1PRE : 3;
  59.             reg32_t I2SSRC : 1;
  60.             reg32_t MCO1 : 2;
  61.             reg32_t RTCPRE : 5;
  62.             reg32_t PPRE2 : 3;
  63.             reg32_t PPRE1 : 3;
  64.             reg32_t : 2;
  65.             reg32_t HPRE : 4;
  66.             reg32_t SWS : 2;
  67.             reg32_t SW : 2;
  68.         } bits;
  69.     } CFGR;
  70.     reg32_t CIR;
  71.     reg32_t AHB1RSTR;
  72.     reg32_t AHB2RSTR;
  73.     reg32_t : 32;
  74.     reg32_t : 32;
  75.     reg32_t APB1RSTR;
  76.     reg32_t APB2RSTR;
  77.     reg32_t : 32;
  78.     reg32_t : 32;
  79.     union {
  80.         reg32_t reg;
  81.         struct {
  82.             reg32_t : 9;
  83.             reg32_t DMA2EN : 1;
  84.             reg32_t DMA1EN : 1;
  85.             reg32_t : 8;
  86.             reg32_t CRCEN : 1;
  87.             reg32_t : 4;
  88.             reg32_t GPIOHEN : 1;
  89.             reg32_t : 2;
  90.             reg32_t GPIOEEN : 1;
  91.             reg32_t GPIODEN : 1;
  92.             reg32_t GPIOCEN : 1;
  93.             reg32_t GPIOBEN : 1;
  94.             reg32_t GPIOAEN : 1;
  95.         } bits;
  96.     } AHB1ENR;
  97.     reg32_t AHB2ENR;
  98.     reg32_t : 32;
  99.     reg32_t : 32;
  100.     union {
  101.         reg32_t reg;
  102.         struct {
  103.             reg32_t : 3;
  104.             reg32_t PWREN : 1;
  105.             reg32_t : 4;
  106.             reg32_t I2C3EN : 1;
  107.             reg32_t I2C2EN : 1;
  108.             reg32_t I2C1EN : 1;
  109.             reg32_t : 3;
  110.             reg32_t USART2EN : 1;
  111.             reg32_t : 1;
  112.             reg32_t SPI3EN : 1;
  113.             reg32_t SPI2EN : 1;
  114.             reg32_t : 2;
  115.             reg32_t WWDGEN : 1;
  116.             reg32_t : 7;
  117.             reg32_t TIM5EN : 1;
  118.             reg32_t TIM4EN : 1;
  119.             reg32_t TIM3EN : 1;
  120.             reg32_t TIM2EN : 1;
  121.         } bits;
  122.     } APB1ENR;
  123.     union {
  124.         reg32_t reg;
  125.         struct {
  126.             reg32_t : 13;
  127.             reg32_t TIM11EN : 1;
  128.             reg32_t TIM10EN : 1;
  129.             reg32_t TIM9EN : 1;
  130.             reg32_t : 1;
  131.             reg32_t SYSCFGEN : 1;
  132.             reg32_t SPI4EN : 1;
  133.             reg32_t SPI1EN : 1;
  134.             reg32_t SDIOEN : 1;
  135.             reg32_t : 2;
  136.             reg32_t ADC1EN : 1;
  137.             reg32_t : 2;
  138.             reg32_t USART6EN : 1;
  139.             reg32_t USART1EN : 1;
  140.             reg32_t : 3;
  141.             reg32_t TIM1EN : 1;
  142.         } bits;
  143.     } APB2ENR;
  144.     reg32_t : 32;
  145.     reg32_t : 32;
  146.     reg32_t AHB1LPENR;
  147.     reg32_t AHB2LPENR;
  148.     reg32_t : 32;
  149.     reg32_t : 32;
  150.     reg32_t APB1LPENR;
  151.     reg32_t APB2LPENR;
  152.     reg32_t : 32;
  153.     reg32_t : 32;
  154.     reg32_t BDCR;
  155.     reg32_t CSR;
  156.     reg32_t : 32;
  157.     reg32_t : 32;
  158.     reg32_t SSCGR;
  159.     reg32_t PLLI2SCFGR;
  160.     reg32_t : 32;
  161.     reg32_t DCKCFGR;
  162.  
  163.   public:
  164.     /**
  165.      * @brief 3 PLL register scaler values
  166.      */
  167.     struct PLLClocks {
  168.         uint32_t pll_m;
  169.         uint32_t pll_n;
  170.         uint32_t pll_p;
  171.     };
  172.  
  173.     /**
  174.      * @brief Frequency of external oscillator
  175.      */
  176.     static constexpr int HSE_CRYSTAL_FREQ_HZ = 25000000;
  177.     /**
  178.      * @brief Frequency of internal oscillator
  179.      */
  180.     static constexpr int HSI_CRYSTAL_FREQ_HZ = 16000000;
  181.     /**
  182.      * @brief Target CPU frequency
  183.      */
  184.     static constexpr int TARGET_SYSTEM_CLOCK = 84000000;
  185.  
  186.     /**
  187.      * @brief Maximum recommended VCO input frequency
  188.      * @note Documented in MCU datasheet PLL electrical characteristics documentation
  189.      */
  190.     static constexpr int VCO_INPUT_FREQUENCY_CEILING = 2000000;
  191.     /**
  192.      * @brief Maximum system clock frequency
  193.      * @note Documented in MCU datasheet PLL electrical characteristics documentation
  194.      */
  195.     static constexpr int SYSTEM_CLOCK_FREQUENCY_CEILING = 84000000;
  196.     /**
  197.      * @brief Maximum internal PLL clock frequency
  198.      * @note Documented in MCU datasheet PLL electrical characteristics documentation
  199.      */
  200.     static constexpr int PLL_INTERNAL_FREQUENCY_CEILING = 432000000;
  201.     /**
  202.      * @brief Manual timeout value for HSE ready
  203.      *
  204.      */
  205.     static constexpr int HSE_TIMEOUT = 1000;
  206.  
  207.     RCC();
  208.  
  209.     void *operator new(std::size_t);
  210.  
  211.     void EnableExternalSystemClock();
  212.  
  213.     /**
  214.      * @brief Enables clock signal to specific GPIO peripheral
  215.      *
  216.      * @param selection GPIO selection enum value
  217.      */
  218.     inline void EnableGPIO(const GPIO::Selection selection) {
  219.         this->AHB1ENR.reg |= (1 << selection);
  220.     }
  221.  
  222.     inline void DisableGPIO(const enum GPIO::Selection selection) {
  223.         this->AHB1ENR.reg &= ~(1 << selection);
  224.     }
  225.  
  226.     /**
  227.      * @brief Calculate system clock frequency through PLL register values
  228.      *
  229.      * @param hs_crystal_freq HS clock signal frequency in Hz
  230.      * @param pll_m M divisor
  231.      * @param pll_n N mulitplier
  232.      * @param pll_p P divisor in register form
  233.      * @return constexpr int System clock frequency
  234.      */
  235.     static constexpr int CalculateSysClock(uint32_t hs_crystal_freq, uint32_t pll_m, uint32_t pll_n,
  236.                                            uint32_t pll_p) {
  237.         return ((hs_crystal_freq / pll_m) * pll_n) / ((pll_p * 2) + 2);
  238.     }
  239.  
  240.     /**
  241.      * @brief Returns best match for PLL M, N, and P register values for main MCU PLL
  242.      *
  243.      * @param hs_crystal_freq Input HS clock signal frequency in Hz
  244.      * @param target Target system clock frequency
  245.      * @return constexpr struct PLLClocks M, N, and P values in struct
  246.      */
  247.     static constexpr struct PLLClocks CalculatePLLClocks(uint32_t hs_crystal_freq,
  248.                                                          uint32_t target) {
  249.         uint32_t pll_m = 1, optimum_pll_n = 0, optimum_pll_p = 0;
  250.         int64_t min_diff = INT64_MAX;
  251.  
  252.         // Calculate PLL M value to satisfy frequency constraints
  253.         while (hs_crystal_freq / pll_m > RCC::VCO_INPUT_FREQUENCY_CEILING) {
  254.             pll_m++;
  255.         }
  256.  
  257.         // Iterate through all values of N and P to find closest match to target
  258.         for (uint32_t pll_n = 430; pll_n > 50; pll_n--) {
  259.             for (uint32_t pll_p = 2; pll_p <= 8; pll_p += 2) {
  260.                 // Calculate system clock with crystal, M, N, and P
  261.                 uint32_t clock =
  262.                     RCC::CalculateSysClock(hs_crystal_freq, pll_m, pll_n, (pll_p - 2) / 2);
  263.                 if ((hs_crystal_freq / pll_m) * pll_n < RCC::PLL_INTERNAL_FREQUENCY_CEILING &&
  264.                     clock < RCC::SYSTEM_CLOCK_FREQUENCY_CEILING) {
  265.                     // Calcualte absolute difference between target and calculated clock
  266.                     int64_t diff = (static_cast<int64_t>(target) - static_cast<int64_t>(clock));
  267.                     diff *= ((diff < 0) ? -1 : 1);
  268.  
  269.                     // If it's closer than previously saved result, overwrite it
  270.                     if (diff <= min_diff) {
  271.                         min_diff = diff;
  272.                         optimum_pll_n = pll_n;
  273.                         optimum_pll_p = pll_p;
  274.                     }
  275.                 }
  276.             }
  277.         }
  278.  
  279.         // Return closest answer in register form
  280.         return {pll_m, optimum_pll_n, (optimum_pll_p - 2) / 2};
  281.     }
  282.  
  283.     /**
  284.      * @brief Calculate system clock frequency through target clock frequency
  285.      *
  286.      * @param hs_crystal_freq HS clock signal frequency in Hz
  287.      * @return constexpr int System clock frequency
  288.      */
  289.     static constexpr int GetSystemClock(uint32_t hs_crystal_freq) {
  290.         auto pll_clocks = RCC::CalculatePLLClocks(hs_crystal_freq, RCC::TARGET_SYSTEM_CLOCK);
  291.  
  292.         return RCC::CalculateSysClock(HSE_CRYSTAL_FREQ_HZ, pll_clocks.pll_m, pll_clocks.pll_n,
  293.                                       pll_clocks.pll_p);
  294.     }
  295.  
  296.     /**
  297.      * @brief Calculate APB2 clock prescaler
  298.      *
  299.      * @param sys_clock Current system clock
  300.      * @return constexpr int APB2 prescaler value
  301.      */
  302.     static constexpr int CalculateLSAPB2Prescaler(uint32_t sys_clock) {
  303.         int divisor = 1;
  304.  
  305.         while (sys_clock / divisor > 42000000) {
  306.             divisor *= 2;
  307.         }
  308.  
  309.         switch (divisor) {
  310.             case 1:
  311.                 return 0b000;
  312.             case 2:
  313.                 return 0b100;
  314.             case 4:
  315.                 return 0b101;
  316.             case 8:
  317.                 return 0b110;
  318.             case 16:
  319.                 return 0b111;
  320.         }
  321.     }
  322. };
  323.  
  324. static_assert(sizeof(RCC) == 36 * sizeof(reg32_t), "RCC contains padding bytes.");
  325. static_assert(std::is_standard_layout<RCC>::value, "RCC isn't standard layout.");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement