Move rtc control to new BKP module

RCC's BCDR register has been moved to the BKP module since it is part of
the backup circuit and thus also aboeys some restrictions access-wise
This commit is contained in:
Steins7 2024-07-27 20:07:36 +02:00
parent 3e3d4d2bff
commit 507f1e6863
8 changed files with 250 additions and 212 deletions

125
drv/bkp.c Normal file
View File

@ -0,0 +1,125 @@
/** @file bkp.c
* Module handling the Backup (BKP) domain functionalities.
*
*/
//--includes--------------------------------------------------------------------
#include "bkp.h"
#include "bkp_regs.h"
#include "rcc.h"
#include "nvic.h"
//--local definitions-----------------------------------------------------------
uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src);
//--local variables-------------------------------------------------------------
static volatile struct BKP* bkp_regs = (struct BKP*)BKP_BASE_ADDRESS;
static volatile struct RCC* rcc_regs = (struct RCC*)RCC_BASE_ADDRESS;
static volatile struct RTC* rtc_regs = (struct RTC*)RTC_BASE_ADDRESS;
static BkpRtcCallback rtc_callback;
//--public functions------------------------------------------------------------
void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src,
enum BkpRtcIrq irq_mask, uint32_t alarm_tick, BkpRtcCallback callback)
{
rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE);
//start RTC
rcc_regs->BDCR.RTCSEL = clock_src + 1;
rcc_regs->BDCR.RTCEN = 1;
//compute prescaler
uint32_t prescaler = compute_prescaler(period_ms, clock_src);
//wait for registers to synchronize
rtc_regs->CRL.RSF = 0;
while (rtc_regs->CRL.RSF != 1) {}
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
//enable core configuration
rtc_regs->CRL.CNF = 1;
//configure core registers
rtc_regs->PRLH.PRL = prescaler >> 16;
rtc_regs->PRLL.PRL = prescaler;
rtc_regs->ALRH.RTC_ALR = alarm_tick >> 16;
rtc_regs->ALRL.RTC_ALR = alarm_tick;
//apply irq config
rtc_regs->CRH.word |= irq_mask & 0x7;
//disable/apply core configuration
rtc_regs->CRL.CNF = 0;
//wait for last operation to finish
while (rtc_regs->CRL.RTOFF != 1) {}
if (callback) {
rtc_callback = callback;
nvic_enable(NVIC_IRQ_RTC);
}
}
uint32_t bkp_read_rtc(void)
{
//wait for core registers to be synchronized, immediate most of the time
while (rtc_regs->CRL.RSF != 1) {}
uint32_t time = rtc_regs->CNTH.RTC_CNT << 16;
time |= rtc_regs->CNTL.RTC_CNT << 0;
return time;
}
void bkp_reset(void)
{
rcc_regs->BDCR.BDRST = 1;
rcc_regs->BDCR.BDRST = 0;
}
//--local functions-------------------------------------------------------------
uint32_t compute_prescaler(uint32_t period_ms, enum BkpRtcClockSrc clock_src)
{
uint32_t prescaler;
switch (clock_src) {
case BKP_RTC_CLOCK_SRC_LSE:
prescaler = 32768000; //32.768kHz
break;
case BKP_RTC_CLOCK_SRC_LSI:
prescaler = 40000000; //40khz
break;
case BKP_RTC_CLOCK_SRC_HSE:
prescaler = 62500000; //8Mhz / 128
break;
default:
return 0;
}
return prescaler / period_ms;
}
//--ISRs------------------------------------------------------------------------
void hdr_rtc(void)
{
nvic_clear_pending(NVIC_IRQ_RTC);
//copy and clear and pass along src flags
enum BkpRtcIrq src = rtc_regs->CRL.word & 0x7;
rtc_regs->CRL.word &= ~(0x7);
rtc_callback(src);
}

47
drv/bkp.h Normal file
View File

@ -0,0 +1,47 @@
/** @file bkp.h
* Module handling the Backup (BKP) domain functionalities.
*
*/
#ifndef _BKP_H_
#define _BKP_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
enum BkpRtcClockSrc {
BKP_RTC_CLOCK_SRC_LSE = 0x0,
BKP_RTC_CLOCK_SRC_LSI = 0x1,
BKP_RTC_CLOCK_SRC_HSE = 0x2,
};
enum BkpRtcIrq {
BKP_RTC_IRQ_NONE = 0,
BKP_RTC_IRQ_SECOND = 0x1 << 0,
BKP_RTC_IRQ_ALARM = 0x1 << 1,
BKP_RTC_IRQ_OVERFLOW = 0x1 << 2,
};
typedef void (*BkpRtcCallback)(enum BkpRtcIrq src);
//--functions-------------------------------------------------------------------
void bkp_configure_rtc(uint32_t period_ms, enum BkpRtcClockSrc clock_src,
enum BkpRtcIrq irq_mask, uint32_t alarm_tick, BkpRtcCallback callback);
uint32_t bkp_read_rtc(void);
void bkp_reset(void);
//unimplemented functions
void bkp_configure_tamper();
void bkp_calibrate_lsi(void);
void bkp_configure_lse(bool enable);
#endif //_BKP_H_

View File

@ -1,13 +1,13 @@
/** @file rtc_regs.h
* Module defining the Real-Time Clock (RTC) registers.
/** @file bkp_regs.h
* Module defining the Backup (bkp) domain registers.
*
* Mainly made to be used by the rtc module. It is recommanded to go through
* Mainly made to be used by the bkp module. It is recommanded to go through
* the functions provided by that module instead of directly using the registers
* defined here.
*/
#ifndef _RTC_REGS_H_
#define _RTC_REGS_H_
#ifndef _BKP_REGS_H_
#define _BKP_REGS_H_
//--includes--------------------------------------------------------------------
@ -16,8 +16,79 @@
//--type definitions------------------------------------------------------------
#define BKP_BASE_ADDRESS 0x40006C00
#define RCC_BASE_ADDRESS 0x40021020
#define RTC_BASE_ADDRESS 0x40002800
union BKP_DR {
struct {
uint32_t D:16;
uint32_t reserved1:16;
};
uint32_t word;
};
union BKP_RTCCR {
struct {
uint32_t CAL:7;
uint32_t CCO:1;
uint32_t ASOE:1;
uint32_t ASOS:1;
uint32_t reserved1:22;
};
uint32_t word;
};
union BKP_CR {
struct {
uint32_t TPE:1;
uint32_t TPAL:1;
uint32_t reserved1:30;
};
uint32_t word;
};
union BKP_CSR {
struct {
uint32_t CTE:1;
uint32_t CTI:1;
uint32_t TPIE:1;
uint32_t reserved1:5;
uint32_t TEF:1;
uint32_t TIF:1;
uint32_t reserved2:22;
};
uint32_t word;
};
struct BKP {
union BKP_DR DR[20];
union BKP_RTCCR RTCCR;
union BKP_CR CR;
union BKP_CSR CSR;
};
union RCC_BDCR {
struct {
uint32_t LSEON:1;
uint32_t LSERDY:1;
uint32_t LSEBYP:1;
uint32_t reserved1:5;
uint32_t RTCSEL:2;
uint32_t reserved2:5;
uint32_t RTCEN:1;
uint32_t BDRST:1;
uint32_t reserved3:15;
};
uint32_t word;
};
struct RCC {
union RCC_BDCR BDCR;
};
union RTC_CRH {
struct {
uint32_t SECIE:1;
@ -121,5 +192,5 @@ struct RTC {
//--functions-------------------------------------------------------------------
#endif //_RTC_REGS_H_
#endif //_BKP_REGS_H_

View File

@ -70,12 +70,6 @@ void rcc_configure_lsi(bool enable)
}
}
void rcc_configure_rtc(bool enable, enum RccRtcClockSrc clock_src)
{
regs->BDCR.RTCSEL = clock_src;
regs->BDCR.RTCEN = enable;
}
void rcc_enable(enum RccAhb ahb_mask, enum RccApb1 apb1_mask,
enum RccApb2 apb2_mask)
{

View File

@ -125,8 +125,6 @@ void rcc_configure(enum RccPreset preset);
*/
void rcc_configure_lsi(bool enable);
void rcc_configure_rtc(bool enable, enum RccRtcClockSrc clock_src);
/**
* Enables peripherals on the different buses. The enums values can used as
* masks to enable multiple peripherals at the same time. Invalid values will be

View File

@ -225,21 +225,6 @@ union RCC_APB1ENR {
uint32_t word;
};
union RCC_BDCR {
struct {
uint32_t LSEON:1;
uint32_t LSERDY:1;
uint32_t LSEBYP:1;
uint32_t reserved1:5;
uint32_t RTCSEL:2;
uint32_t reserved2:5;
uint32_t RTCEN:1;
uint32_t BDRST:1;
uint32_t reserved3:15;
};
uint32_t word;
};
union RCC_CSR {
struct {
uint32_t LSION:1;
@ -266,7 +251,7 @@ struct RCC {
union RCC_AHBENR AHBENR;
union RCC_APB2ENR APB2ENR;
union RCC_APB1ENR APB1ENR;
union RCC_BDCR BDCR;
uint32_t reserved1;
union RCC_CSR CSR;
};

139
drv/rtc.c
View File

@ -1,139 +0,0 @@
//--includes--------------------------------------------------------------------
#include "rtc.h"
#include "rtc_regs.h"
#include "rcc.h"
#include "pwr.h"
#include "nvic.h"
//--local definitions-----------------------------------------------------------
//--local variables-------------------------------------------------------------
static volatile struct RTC* regs = (struct RTC*)RTC_BASE_ADDRESS;
static RtcCallback rtc_callback;
//--public functions------------------------------------------------------------
void rtc_configure(uint32_t period_ms, enum RtcClockSrc clock_src,
enum RtcIrq irq_mask, uint32_t alarm_tick, RtcCallback callback)
{
pwr_configure_bkp_write(true);
//start RTC
rcc_configure_rtc(true, clock_src + 1);
//rtc_reset();
rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE);
//rcc_configure_rtc(false, RCC_RTC_CLOCK_SRC_NONE);
//compute prescaler
uint32_t prescaler = 0;
switch (clock_src) {
case RTC_CLOCK_SRC_LSE:
prescaler = 32768000; //32.768kHz
break;
case RTC_CLOCK_SRC_LSI:
prescaler = 40000000; //40khz
break;
case RTC_CLOCK_SRC_HSE:
prescaler = 62500000; //8Mhz / 128
break;
default:
return;
}
prescaler /= period_ms;
//wait for registers to synchronize
regs->CRL.RSF = 0;
while (regs->CRL.RSF != 1) {}
//wait for last operation to finish
while (regs->CRL.RTOFF != 1) {}
//enable core configuration
regs->CRL.CNF = 1;
//configure core registers
regs->PRLH.PRL = prescaler >> 16;
regs->PRLL.PRL = prescaler;
regs->ALRH.RTC_ALR = alarm_tick >> 16;
regs->ALRL.RTC_ALR = alarm_tick;
//apply irq config
regs->CRH.word |= irq_mask & 0x7;
//disable/apply core configuration
regs->CRL.CNF = 0;
//wait for last operation to finish
while (regs->CRL.RTOFF != 1) {}
pwr_configure_bkp_write(false);
if (callback) {
rtc_callback = callback;
nvic_enable(NVIC_IRQ_RTC);
}
}
void rtc_reset(void)
{
nvic_disable(NVIC_IRQ_RTC);
pwr_configure_bkp_write(true);
rcc_enable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE);
//wait for registers to synchronize
regs->CRL.RSF = 0;
//while (regs->CRL.RSF != 1) {}
//wait for last operation to finish
while (regs->CRL.RTOFF != 1) {}
//clear config registers
regs->CRH.word &= ~0x7;
regs->CRL.word &= ~0xf;
//enable core configuration
regs->CRL.CNF = 1;
//reset core registers. DIV register can be ignore since it is reset on any
//changes of the other 2
regs->PRLH.PRL = 0x0;
regs->PRLL.PRL = 0x8000;
regs->CNTH.RTC_CNT = 0x0;
regs->CNTL.RTC_CNT = 0x0;
//disable/apply core configuration
regs->CRL.CNF = 0;
//wait for last operation to finish
while (regs->CRL.RTOFF != 1) {}
rcc_configure_rtc(false, RCC_RTC_CLOCK_SRC_NONE);
rcc_disable(RCC_AHB_NONE, RCC_APB1_BKP, RCC_APB2_NONE);
pwr_configure_bkp_write(false);
}
uint32_t stk_read_s(void)
{
//wait for core registers to be synchronized, immediate most of the time
while (regs->CRL.RSF != 1) {}
uint32_t time = regs->CNTH.RTC_CNT << 16;
time |= regs->CNTL.RTC_CNT << 0;
return time;
}
//--local functions-------------------------------------------------------------
void hdr_rtc(void)
{
nvic_clear_pending(NVIC_IRQ_RTC);
//copy and clear and pass along src flags
enum RtcIrq src = regs->CRL.word & 0x7;
regs->CRL.word &= ~(0x7);
rtc_callback(src);
}

View File

@ -1,43 +0,0 @@
/** @file rtc.h
* Module handling the Real-Time Clock (RTC).
*
*/
#ifndef _RTC_H_
#define _RTC_H_
//--includes--------------------------------------------------------------------
#include "stdint.h"
//--type definitions------------------------------------------------------------
enum RtcClockSrc {
RTC_CLOCK_SRC_LSE = 0x0,
RTC_CLOCK_SRC_LSI = 0x1,
RTC_CLOCK_SRC_HSE = 0x2,
};
enum RtcIrq {
RTC_IRQ_NONE = 0,
RTC_IRQ_SECOND = 0x1 << 0,
RTC_IRQ_ALARM = 0x1 << 1,
RTC_IRQ_OVERFLOW = 0x1 << 2,
};
typedef void (*RtcCallback)(enum RtcIrq src);
//--functions-------------------------------------------------------------------
void rtc_configure(uint32_t period_ms, enum RtcClockSrc clock_src,
enum RtcIrq irq_mask, uint32_t alarm_tick, RtcCallback callback);
void rtc_reset(void);
uint32_t stk_read_s(void);
#endif //_RTC_H_