Skip to content

Commit

Permalink
[stm32] Add RTC peripheral
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Dec 22, 2024
1 parent 9c06e6c commit 91ee5c9
Show file tree
Hide file tree
Showing 10 changed files with 693 additions and 5 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,30 @@ Please [discover modm's peripheral drivers for your specific device][discover].
<td align="center">✕</td>
<td align="center">✕</td>
</tr><tr>
<td align="left">RTC</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">✅</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">✕</td>
<td align="center">✕</td>
<td align="center">✕</td>
</tr><tr>
<td align="left">SPI</td>
<td align="center">✅</td>
<td align="center">✅</td>
Expand Down
1 change: 1 addition & 0 deletions src/modm/math/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@
#include "utils/operator.hpp"
#include "utils/endianness.hpp"
#include "utils/crc.hpp"
#include "utils/bcd.hpp"

#endif // MODM_MATH_UTILS_HPP
53 changes: 53 additions & 0 deletions src/modm/math/utils/bcd.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#ifndef MODM_MATH_BCD_HPP
#define MODM_MATH_BCD_HPP

#include <stdint.h>

namespace modm
{

/// @ingroup modm_math_utils
/// @{

constexpr uint32_t
fromBcd(uint32_t bcd)
{
uint32_t decimal = 0;
for (uint16_t multiplier = 1; bcd != 0; multiplier *= 10)
{
decimal += (bcd & 0b1111) * multiplier;
bcd >>= 4;
}
return decimal;
}

constexpr uint32_t
toBcd(uint32_t decimal)
{
uint32_t bcd = 0;
uint16_t remainder = decimal % 10;
for (uint16_t shift = 0; decimal != 0; shift += 4)
{
bcd |= remainder << shift;
decimal = (decimal - remainder) / 10;
remainder = decimal % 10;
}
return bcd;
}

/// @}

} // namespace modm

#endif // MODM_MATH_BCD_HPP
7 changes: 6 additions & 1 deletion src/modm/platform/clock/stm32/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ def build(env):
nper = "DSI"
if "Eth" in all_peripherals and per == "ETHMAC":
per = "Eth"
if "Rtc" in all_peripherals and per == "RTCAPB":
per = "RTC"
nper = "RTCAPB"
# Fix USBOTG OTG
if target.family == "u5" and per == "OTG":
per = "Usbotgfs"
Expand All @@ -200,7 +203,9 @@ def build(env):
if per.capitalize() not in all_peripherals:
continue
if "EN" in mode:
rcc_enable[per.capitalize()] = (nper, mode["EN"])
kw = per.capitalize()
if kw not in rcc_enable:
rcc_enable[kw] = (nper, mode["EN"])
if "RST" in mode:
rcc_reset[per.capitalize()] = (nper, mode["RST"])

Expand Down
12 changes: 8 additions & 4 deletions src/modm/platform/core/stm32/startup_platform.c.in
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,17 @@ __modm_initialize_platform(void)
// Enable Data Tighly Coupled Memory (DTCM) and backup SRAM (BKPSRAM)
RCC->AHB1ENR |= RCC_AHB1ENR_DTCMRAMEN | RCC_AHB1ENR_BKPSRAMEN;
%% elif target.family in ["g0", "g4", "l4", "l5"]
%% if target.family in ["l4", "g4"]
%% if target.family in ["l4", "g4"]
RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;
%% elif target.family != "g0"
#ifdef PWR_CR2_IOSV
%% elif target.family in ["g0"]
RCC->APBENR1 |= RCC_APBENR1_PWREN;
%% else
#ifdef RCC_APB1ENR1_PWREN
RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;
#endif
%% endif
%% endif
// Enable access to RTC and Backup registers
PWR->CR1 |= PWR_CR1_DBP;

#ifdef PWR_CR2_IOSV
// Enable VDDIO2
Expand Down
35 changes: 35 additions & 0 deletions src/modm/platform/rtc/stm32/module.lb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen
#
# This file is part of the modm project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# -----------------------------------------------------------------------------

def init(module):
module.name = ":platform:rtc"
module.description = "Real Time Clock (RTC)"

def prepare(module, options):
device = options[":target"]
if not device.has_driver("rtc:stm32*"):
return False

module.depends(
":cmsis:device",
":platform:rcc",
":architecture:register",
":math:utils",
":math:units"
)

return True

def build(env):
env.outbasepath = "modm/src/modm/platform/rtc"
env.copy("rtc.hpp")
env.copy("rtc_impl.hpp")
202 changes: 202 additions & 0 deletions src/modm/platform/rtc/stm32/rtc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
* Copyright (c) 2023, Rasmus Kleist Hørlyck Sørensen
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#ifndef MODM_STM32_RTC_HPP
#define MODM_STM32_RTC_HPP

#include <chrono>
#include <ctime>

#include <modm/architecture/interface/clock.hpp>
#include <modm/architecture/interface/register.hpp>

namespace modm::platform
{

/**
* Real Time Clock (RTC) control for STM32 devices
*
* @author Rasmus Kleist Hørlyck Sørensen
* @ingroup modm_platform_rtc
*/
class Rtc
{
static constexpr uint16_t century{2000};
static constexpr uint32_t seconds_per_day{24*60*60};
static constexpr uint32_t seconds_per_year{365*seconds_per_day};
// Unix time starts in 1970, so we need to add 7 leap days until 2000
static constexpr uint32_t seconds_since_base{30*seconds_per_year + 7*seconds_per_day};
static constexpr uint16_t m2d[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};

public:
using duration = std::chrono::duration<int64_t, std::milli>;
using rep = duration::rep;
using period = duration::period;
using time_point = std::chrono::time_point<Rtc, duration>;
static constexpr bool is_steady = true;

/// Efficient representation of a date and time direct from the RTC
class DateTime
{
friend class Rtc;
uint8_t _year;
uint8_t _month;
uint8_t _day;
uint8_t _weekday;

uint8_t _hour;
uint8_t _minute;
uint8_t _second;
bool _isDST;

uint16_t _subseconds;
uint16_t _subfractions;

public:
std::chrono::year inline year() const { return std::chrono::year{_year + century}; }
std::chrono::month inline month() const { return std::chrono::month{_month}; }
std::chrono::day inline day() const { return std::chrono::day{_day}; }
std::chrono::weekday inline weekday() const { return std::chrono::weekday{_weekday}; }

std::chrono::hours inline hour() const { return std::chrono::hours{_hour}; }
std::chrono::minutes inline minute() const { return std::chrono::minutes{_minute}; }
std::chrono::seconds inline second() const { return std::chrono::seconds{_second}; }

float inline
subsecond() const
{ return float(_subfractions - _subseconds) / (_subfractions + 1); }

std::chrono::milliseconds inline
millisecond() const
{ return std::chrono::milliseconds{(_subfractions - _subseconds) * 1'000ul / (_subfractions + 1)}; }

bool inline isDST() const { return _isDST; }

std::chrono::days inline
day_of_year() const
{
uint16_t yday = m2d[_month] + _day;
if (_month > 2 and year().is_leap()) yday++;
return std::chrono::days{yday};
}

std::tm tm() const;

std::time_t time() const;

time_point inline
now() const noexcept
{ return time_point{duration{time()*1000ull + millisecond().count()}}; }
};
friend class DateTime;

public:
static time_point
now() noexcept
{ return dateTime().now(); }

public:
static void
enable();

static void
disable();

template< class SystemClock >
static bool
initialize();

static const DateTime&
dateTime();

template< class DateTimeClass >
static void
setDateTime(const DateTimeClass &dateTime);

/**
* Synchronized to a remote clock with a high degree of precision
*
* @tparam Rep
* an arithmetic type representing the number of ticks
* @tparam Period
* a std::ratio representing the tick period (i.e. the number of second's fractions per tick)
*
* @param delay The amount of time to delay (or advance) the
* @param waitCycle Number of cycles to wait for the INITF bit to be set. (default = 2048)
*
* @return True on success
*/
template< typename Rep, typename Period >
static bool
synchronize(std::chrono::duration<Rep, Period> delay, uint32_t waitCycles = 2048);

public:

enum class
Interrupt : uint32_t
{
InternalTimestamp = RTC_CR_ITSE,
Timestamp = RTC_CR_TSIE,
WakeupTimer = RTC_CR_WUTIE,
AlarmB = RTC_CR_ALRBIE,
AlarmA = RTC_CR_ALRAIE,
};
MODM_FLAGS32(Interrupt);

enum class
InterruptFlag : uint32_t
{
InternalTimestamp = RTC_SR_ITSF,
TimestampOverflow = RTC_SR_TSOVF,
Timestamp = RTC_SR_TSF,
WakeupTimer = RTC_SR_WUTF,
AlarmB = RTC_SR_ALRBF,
AlarmA = RTC_SR_ALRAF,
};
MODM_FLAGS32(InterruptFlag);

static void
enableInterruptVector(bool enable, uint32_t priority);

static void
enableInterrupt(Interrupt_t interrupt);

static void
disableInterrupt(Interrupt_t interrupt);

static InterruptFlag_t
getInterruptFlags();

/**
*
*
* @warning Not all InterruptFlags can be cleared this way.
*/
static void
acknowledgeInterruptFlag(InterruptFlag_t flags);

private:
/// Unlock RTC register write protection
static void
unlock();

/// Lock RTC register write protection
static void
lock();

static inline DateTime idt{};
};

} // namespace modm::platform

#include "rtc_impl.hpp"

#endif // MODM_STM32_RTC_HPP
Loading

0 comments on commit 91ee5c9

Please sign in to comment.