Skip to content

File clock.hpp

File List > include > libhal-stm32f1 > clock.hpp

Go to the documentation of this file

// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include "constants.hpp"

#include <libhal/error.hpp>
#include <libhal/units.hpp>

namespace hal::stm32f1 {

using namespace hal::literals;

constexpr auto internal_low_speed_oscillator = 20.0_kHz;

constexpr auto internal_high_speed_oscillator = 8.0_MHz;

constexpr auto flash_clock = internal_high_speed_oscillator;

constexpr auto watchdog_clock_rate = internal_low_speed_oscillator;

enum class apb_divider : std::uint8_t
{
  divide_by_1 = 0,
  divide_by_2 = 0b100,
  divide_by_4 = 0b101,
  divide_by_8 = 0b110,
  divide_by_16 = 0b111,
};

enum class ahb_divider : std::uint8_t
{
  divide_by_1 = 0,
  divide_by_2 = 0b1000,
  divide_by_4 = 0b1001,
  divide_by_8 = 0b1010,
  divide_by_16 = 0b1011,
  divide_by_64 = 0b1100,
  divide_by_128 = 0b1101,
  divide_by_256 = 0b1110,
  divide_by_512 = 0b1111,
};

enum class adc_divider : std::uint8_t
{
  divide_by_2 = 0b00,
  divide_by_4 = 0b01,
  divide_by_6 = 0b10,
  divide_by_8 = 0b11,
};

enum class system_clock_select : std::uint8_t
{
  high_speed_internal = 0b00,
  high_speed_external = 0b01,
  pll = 0b10,
};

enum class pll_multiply : std::uint8_t
{
  multiply_by_2 = 0b0000,
  multiply_by_3 = 0b0001,
  multiply_by_4 = 0b0010,
  multiply_by_5 = 0b0011,
  multiply_by_6 = 0b0100,
  multiply_by_7 = 0b0101,
  multiply_by_8 = 0b0110,
  multiply_by_9 = 0b0111,
  multiply_by_10 = 0b1000,
  multiply_by_11 = 0b1001,
  multiply_by_12 = 0b1010,
  multiply_by_13 = 0b1011,
  multiply_by_14 = 0b1100,
  multiply_by_15 = 0b1101,
  multiply_by_16 = 0b1110,
};

enum class rtc_source : std::uint8_t
{
  no_clock = 0b00,
  low_speed_internal = 0b01,
  low_speed_external = 0b10,
  high_speed_external_divided_by_128 = 0b11,
};

enum class pll_source : std::uint8_t
{
  high_speed_internal = 0b0,
  high_speed_external = 0b1,
  high_speed_external_divided_by_2 = 0b11,
};

enum class usb_divider : std::uint8_t
{
  divide_by_1 = 1,
  divide_by_1_point_5 = 0,
};

struct clock_tree
{
  hal::hertz high_speed_external = 0.0_MHz;

  hal::hertz low_speed_external = 0.0_MHz;

  struct pll_t
  {
    bool enable = false;
    pll_source source = pll_source::high_speed_internal;
    pll_multiply multiply = pll_multiply::multiply_by_2;
    struct usb_divider_t
    {
      usb_divider divider = usb_divider::divide_by_1_point_5;
    } usb = {};
  } pll = {};

  system_clock_select system_clock = system_clock_select::high_speed_internal;

  struct rtc_t
  {
    bool enable = false;
    rtc_source source = rtc_source::low_speed_internal;
  } rtc = {};

  struct ahb_t
  {
    ahb_divider divider = ahb_divider::divide_by_1;
    struct apb1_t
    {
      apb_divider divider = apb_divider::divide_by_1;
    } apb1 = {};

    struct apb2_t
    {
      apb_divider divider = apb_divider::divide_by_1;
      struct adc_t
      {
        adc_divider divider = adc_divider::divide_by_2;
      } adc = {};
    } apb2 = {};
  } ahb = {};
};

void configure_clocks(clock_tree p_clock_tree);

hal::hertz frequency(peripheral p_id);
}  // namespace hal::stm32f1