Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stm32] Adding Real Time Clock (RTC) for STM32G4 #1055

Draft
wants to merge 38 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
899449d
[hal] Add RTC initialization and synchronization
rasmuskleist Aug 7, 2023
1ca42f9
[hal] Add RTC interrupt functions
rasmuskleist Aug 7, 2023
56659d9
[example] Add RTC test
rasmuskleist Aug 7, 2023
e10b4cb
[math] Adding rolled BCD conversion functions
rasmuskleist Aug 8, 2023
7ca32fe
Use math::utils BCD functions instead
rasmuskleist Aug 8, 2023
ce50925
[test] Add very basic BCD test
rasmuskleist Aug 8, 2023
aca50d1
Include <stdint.h> in bcd.hpp
rasmuskleist Aug 9, 2023
bc4ccc0
[rcc] Allow multiple enable bits in RCC
rasmuskleist Aug 9, 2023
36e0264
Fix enable RTC in Rcc::enable
rasmuskleist Aug 9, 2023
a4ac17f
Clean up enable/disable functions
rasmuskleist Aug 9, 2023
1014ce4
Fix test
rasmuskleist Aug 9, 2023
67897b2
Fix 0x00 inplace of 0x09
rasmuskleist Aug 9, 2023
f9a6be8
Move interrupt enums
rasmuskleist Aug 9, 2023
3481389
Implement synchronize with std::chrono::duration
rasmuskleist Aug 9, 2023
0944588
Make module.lb not overwrite existing rcc_enable
rasmuskleist Aug 9, 2023
8d8571f
Remove unnecessary condition
rasmuskleist Aug 9, 2023
3c8ee1d
White space
rasmuskleist Aug 9, 2023
b6422b5
Use the same wrong WPR key as linux
rasmuskleist Aug 9, 2023
5f88163
Use default prescaler
rasmuskleist Aug 14, 2023
0723beb
sort includes
rasmuskleist Aug 14, 2023
963d6f5
Use int64_t for duration rep
rasmuskleist Aug 16, 2023
208cd65
Remove getPrescaler function
rasmuskleist Aug 16, 2023
0c0169c
[board] Enable RTC using LSE for nucleo_g474re
rasmuskleist Aug 16, 2023
df92454
Fix datetime construction
rasmuskleist Aug 16, 2023
3d9f95b
startup whitespace
rasmuskleist Aug 16, 2023
1309b12
Add friend class and clock frequencies
rasmuskleist Aug 16, 2023
6478700
Update test
rasmuskleist Aug 16, 2023
0a63653
Update initialize
rasmuskleist Aug 16, 2023
25f651d
Remove get prescaler
rasmuskleist Aug 16, 2023
9cadadc
Move unlock and lock functions to .hpp
rasmuskleist Aug 16, 2023
c627c1d
synchronize comment
rasmuskleist Aug 16, 2023
ef6755e
Implement synchronize with integer math
rasmuskleist Aug 16, 2023
a93ef7b
Remove private getPrescaler functions
rasmuskleist Aug 16, 2023
15fa5cb
Move functions to impl and inline
rasmuskleist Aug 16, 2023
fe5ccbc
Remove prescaler struct
rasmuskleist Aug 16, 2023
a815277
Update synchronize docs
rasmuskleist Aug 16, 2023
d044e5d
Check REFCKON before synchronizing
rasmuskleist Aug 16, 2023
5776001
Fix datetime constructor
rasmuskleist Aug 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,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
63 changes: 63 additions & 0 deletions examples/nucleo_g474re/rtc/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// 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/.
*/
// ----------------------------------------------------------------------------

#include <modm/board.hpp>
#include <modm/debug/logger.hpp>
#include <modm/platform.hpp>
#include <modm/processing.hpp>

using namespace modm::literals;

// Set the log level
#undef MODM_LOG_LEVEL
#define MODM_LOG_LEVEL modm::log::INFO

static constexpr Rtc::DateTime datetime = {
.year = 0,
.month = 12,
.date = 31,
.weekday = 1,
.hour = 23,
.minute = 59,
.second = 30,
};

int
main()
{
Board::initialize();

modm::PeriodicTimer timer(std::chrono::milliseconds(1000));

Rtc::initialize<Board::SystemClock>();
while (true)
{
if (timer.execute())
{
float ss;
Rtc::DateTime dt;
if (Rtc::getSubSecond(ss) && Rtc::getDateTime(dt))
{
MODM_LOG_INFO << "Date: " << dt.date << "-" << dt.month << "-" << dt.year << modm::endl;
MODM_LOG_INFO << "Weekday: " << dt.weekday << modm::endl;
MODM_LOG_INFO << "Time: " << dt.hour << ":" << dt.minute << ":" << dt.second << modm::endl;
MODM_LOG_INFO << "Sub Second: " << ss << modm::endl;
}
else
{
MODM_LOG_INFO << "Error: Unable to get Date Time and Sub Second" << modm::endl;
}
}
}

return 0;
}
12 changes: 12 additions & 0 deletions examples/nucleo_g474re/rtc/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<library>
<extends>modm:nucleo-g474re</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_g474re/rtc</option>
</options>
<modules>
<module>modm:debug</module>
<module>modm:platform:rtc</module>
<module>modm:processing:timer</module>
<module>modm:build:scons</module>
</modules>
</library>
3 changes: 3 additions & 0 deletions src/modm/board/nucleo_g474re/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ struct SystemClock
// update frequencies for busy-wait delay functions
Rcc::updateCoreFrequency<Frequency>();

Rcc::enableLowSpeedExternalCrystal();
Rcc::enableRealTimeClock(Rcc::RealTimeClockSource::LowSpeedExternalCrystal);

Rcc::setCanClockSource(Rcc::CanClockSource::Pclk);
return true;
}
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 @@ -179,6 +179,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 @@ -193,7 +196,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[nper] = mode["RST"]

Expand Down
2 changes: 1 addition & 1 deletion src/modm/platform/clock/stm32/rcc_impl.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,4 @@ Rcc::isEnabled()
%% endfor
}

} // namespace modm::platform
} // namespace modm::platform
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

best to change your editor to add a newline at the end of file, otherwise there'll be a lot of these changes in the modm code base ;-P

2 changes: 2 additions & 0 deletions src/modm/platform/core/stm32/startup_platform.c.in
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ __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"]
// Enable access to RTC and Backup registers
PWR->CR1 |= PWR_CR1_DBP;
%% if target.family in ["l4", "g4"]
RCC->APB1ENR1 |= RCC_APB1ENR1_PWREN;
%% elif target.family != "g0"
Expand Down
39 changes: 39 additions & 0 deletions src/modm/platform/rtc/stm32/module.lb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/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 device.identifier.family not in ["g4"]:
return False
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):
target = env[":target"].identifier

env.outbasepath = "modm/src/modm/platform/rtc"
env.template("rtc_impl.hpp.in")
env.template("rtc.cpp.in")
env.template("rtc.hpp.in")
61 changes: 61 additions & 0 deletions src/modm/platform/rtc/stm32/rtc.cpp.in
rasmuskleist marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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/.
*/
// ----------------------------------------------------------------------------

#include "rtc.hpp"

#include <modm/math/utils.hpp>

namespace modm::platform
{

// ----------------------------------------------------------------------------

bool
Rtc::getDateTime(DateTime &dateTime, uint32_t waitCycles)
{
/// TODO: Determine if ABP1 frequency is less than seven times RTC frequency
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You would write this information to a bool member in initialize() and query it here. it's a bit inelegant, but kinda how we do things here.

/// TODO: Determine if BYPSHAD control bit is set or cleared in the RTC_CR register

// After initialization, synchronization software must wait until RSF is set
while (!(RTC->ICSR & RTC_ICSR_RSF))
if (--waitCycles == 0) return false;

dateTime.hour = fromBcd((RTC->TR & (RTC_TR_HT_Msk | RTC_TR_HU_Msk)) >> RTC_TR_HU_Pos);
dateTime.minute = fromBcd((RTC->TR & (RTC_TR_MNT_Msk | RTC_TR_MNU_Msk)) >> RTC_TR_MNU_Pos);
dateTime.second = fromBcd((RTC->TR & (RTC_TR_ST_Msk | RTC_TR_SU_Msk)) >> RTC_TR_SU_Pos);

dateTime.year = fromBcd((RTC->DR & (RTC_DR_YT_Msk | RTC_DR_YU_Msk)) >> RTC_DR_YU_Pos);
dateTime.month = fromBcd((RTC->DR & (RTC_DR_MT_Msk | RTC_DR_MU_Msk)) >> RTC_DR_MU_Pos);
dateTime.date = fromBcd((RTC->DR & (RTC_DR_DT_Msk | RTC_DR_DU_Msk)) >> RTC_DR_DU_Pos);
dateTime.weekday = ((RTC->DR & RTC_DR_WDU_Msk) >> RTC_DR_WDU_Pos);

return true;
}

// ----------------------------------------------------------------------------

bool
Rtc::getSubSecond(float &subsecond, uint32_t waitCycles)
{
// After initialization, synchronization software must wait until RSF is set
while (!(RTC->ICSR & RTC_ICSR_RSF))
if (--waitCycles == 0) return false;

/*
uint32_t predivS = getSynchronousPrescaler();
uint32_t ss = (RTC->SSR & RTC_SSR_SS_Msk) >> RTC_SSR_SS_Pos;
subsecond = float(predivS - ss) / float(predivS + 1);
/// TODO: Handle case when ss > predivS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meh, why not integer math based on milli- or microseconds?

*/
return true;
}

}
Loading