Skip to content

Commit 6f54890

Browse files
committed
Review asynchronous and synchronous prescaler management
RTC_SetClockSource() exported RTC_getPrediv() exported RTC_computePrediv() added Hardened code Signed-off-by: Frederic.Pillon <[email protected]>
1 parent fb48647 commit 6f54890

File tree

2 files changed

+108
-39
lines changed

2 files changed

+108
-39
lines changed

cores/arduino/stm32/rtc.c

+96-38
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,41 @@ static void *callbackUserData = NULL;
5353

5454
static sourceClock_t clkSrc = LSI_CLOCK;
5555
static uint8_t HSEDiv = 0;
56-
static int8_t AsynchPrediv = -1; // 1 to 127
57-
static int16_t SynchPrediv = -1; // 0 to 32767
56+
#if !defined(STM32F1xx)
57+
/* Custom user values */
58+
static int8_t userPredivAsync = -1;
59+
static int16_t userPredivSync = -1;
60+
#endif /* !STM32F1xx */
5861

5962
static hourFormat_t initFormat = HOUR_FORMAT_12;
6063

6164
/* Private function prototypes -----------------------------------------------*/
62-
static void RTC_setClock(sourceClock_t source);
63-
static void RTC_getPrediv(uint32_t *asynch, uint32_t *synch);
65+
static void RTC_initClock(sourceClock_t source);
66+
#if !defined(STM32F1xx)
67+
static void RTC_computePrediv(int8_t *asynch, int16_t *synch);
68+
#endif /* !STM32F1xx */
6469

6570
/* Exported functions --------------------------------------------------------*/
6671

72+
/**
73+
* @brief Set RTC clock source
74+
* @param source: RTC clock source: LSE, LSI or HSE
75+
* @retval None
76+
*/
77+
void RTC_SetClockSource(sourceClock_t source)
78+
{
79+
switch(source) {
80+
case LSI_CLOCK:
81+
case LSE_CLOCK:
82+
case HSE_CLOCK:
83+
clkSrc = source;
84+
break;
85+
default:
86+
clkSrc = LSI_CLOCK;
87+
break;
88+
}
89+
}
90+
6791
/**
6892
* @brief RTC clock initialization
6993
* This function configures the hardware resources used.
@@ -74,7 +98,7 @@ static void RTC_getPrediv(uint32_t *asynch, uint32_t *synch);
7498
* the backup registers) and RCC_CSR register are set to their reset values.
7599
* @retval None
76100
*/
77-
static void RTC_setClock(sourceClock_t source)
101+
static void RTC_initClock(sourceClock_t source)
78102
{
79103
RCC_OscInitTypeDef RCC_OscInitStruct;
80104
RCC_PeriphCLKInitTypeDef PeriphClkInit;
@@ -181,41 +205,64 @@ static void RTC_setClock(sourceClock_t source)
181205
}
182206

183207
/**
184-
* @brief RTC_setPrediv
185-
* Allow to user to set manually the prescaler values.
186-
* @param Asynch: asynchronous prescaler value in range 1 - 127
187-
* @param Synch: synchronous prescaler value in range 0 - 32767
208+
* @brief set user (a)synchronous prescaler values.
209+
* @note use -1 to reset value and use computed ones
210+
* @param asynch: asynchronous prescaler value in range 0 - PREDIVA_MAX
211+
* @param synch: synchronous prescaler value in range 0 - PREDIVS_MAX
188212
* @retval None
189213
*/
190-
void RTC_setPrediv(int8_t Asynch, int16_t Synch)
214+
void RTC_setPrediv(int8_t asynch, int16_t synch)
191215
{
192-
if((Asynch >= 1) && (Synch >= 0)) {
193-
AsynchPrediv = Asynch;
194-
SynchPrediv = Synch;
216+
#if !defined(STM32F1xx)
217+
if((asynch >= -1) && (synch >= -1)) {
218+
userPredivAsync = asynch;
219+
userPredivSync = synch;
195220
}
221+
#else
222+
UNUSED(asynch);
223+
UNUSED(synch);
224+
#endif /* !STM32F1xx */
196225
}
197226

198227
/**
199-
* @brief RTC_getPrediv
200-
* RTC prescalers are set to obtain the RTC clock to 1Hz. See AN4759.
228+
* @brief get user (a)synchronous prescaler values if set else computed ones
229+
* for the current clock source.
201230
* @param asynch: pointer where return asynchronous prescaler value.
202231
* @param synch: pointer where return synchronous prescaler value.
203232
* @retval None
204233
*/
205-
static void RTC_getPrediv(uint32_t *asynch, uint32_t *synch)
234+
void RTC_getPrediv(int8_t *asynch, int16_t *synch)
206235
{
207-
uint32_t predivA;
208-
uint32_t predivS;
209-
uint32_t clk = 0;
210-
211-
if((asynch == NULL) || (synch == NULL)) {
212-
return;
236+
#if !defined(STM32F1xx)
237+
if((userPredivAsync == -1) || (userPredivSync == -1)) {
238+
RTC_computePrediv(asynch, synch);
239+
} else {
240+
if((asynch != NULL) && (synch != NULL)) {
241+
*asynch = userPredivAsync;
242+
*synch = userPredivSync;
243+
}
213244
}
245+
#else
246+
UNUSED(asynch);
247+
UNUSED(synch);
248+
#endif /* !STM32F1xx */
249+
}
250+
251+
#if !defined(STM32F1xx)
252+
/**
253+
* @brief Compute (a)synchronous prescaler
254+
* RTC prescalers are compute to obtain the RTC clock to 1Hz. See AN4759.
255+
* @param asynch: pointer where return asynchronous prescaler value.
256+
* @param synch: pointer where return synchronous prescaler value.
257+
* @retval None
258+
*/
259+
static void RTC_computePrediv(int8_t *asynch, int16_t *synch)
260+
{
261+
uint32_t predivS = PREDIVS_MAX + 1;
262+
uint32_t clk = 0;
214263

215264
// Get user predividers if manually configured
216-
if((AsynchPrediv > 0) && (SynchPrediv > 0)) {
217-
*asynch = AsynchPrediv;
218-
*synch = SynchPrediv;
265+
if((asynch == NULL) || (synch == NULL)) {
219266
return;
220267
}
221268

@@ -232,18 +279,29 @@ static void RTC_getPrediv(uint32_t *asynch, uint32_t *synch)
232279
Error_Handler();
233280
}
234281

235-
// Get prescalers
236-
if(clk > 0) {
237-
for(predivA = 128; predivA > 1; predivA--) {
238-
predivS = clk / predivA;
239-
if((predivS <= 32768) && ((predivS * predivA) == clk)) {
240-
*asynch = predivA - 1;
241-
*synch = predivS - 1;
242-
break;
243-
}
244-
}
282+
/* Find (a)synchronous prescalers to obtain the 1Hz calendar clock */
283+
for(*asynch = PREDIVA_MAX; *asynch >= 0; (*asynch)--) {
284+
predivS = (clk / (*asynch + 1)) - 1;
285+
286+
if(((predivS + 1) * (*asynch + 1)) == clk)
287+
break;
288+
}
289+
290+
/*
291+
* Can't find a 1Hz, so give priority to RTC power consumption
292+
* by choosing the higher possible value for predivA
293+
*/
294+
if((predivS > PREDIVS_MAX) || (*asynch < 0 )) {
295+
*asynch = PREDIVA_MAX;
296+
predivS = (clk / (*asynch + 1)) - 1;
297+
}
298+
299+
if(predivS > PREDIVS_MAX) {
300+
Error_Handler();
245301
}
302+
*synch = (int16_t)predivS;
246303
}
304+
#endif /* !STM32F1xx */
247305

248306
/**
249307
* @brief RTC Initialization
@@ -256,8 +314,8 @@ void RTC_init(hourFormat_t format, sourceClock_t source)
256314
{
257315
initFormat = format;
258316

259-
// Set RTC clock
260-
RTC_setClock(source);
317+
// Init RTC clock
318+
RTC_initClock(source);
261319

262320
RtcHandle.Instance = RTC;
263321

@@ -272,7 +330,7 @@ void RTC_init(hourFormat_t format, sourceClock_t source)
272330
RtcHandle.Init.HourFormat = RTC_HOURFORMAT_24;
273331
}
274332
RtcHandle.Init.OutPut = RTC_OUTPUT_DISABLE;
275-
RTC_getPrediv(&(RtcHandle.Init.AsynchPrediv), &(RtcHandle.Init.SynchPrediv));
333+
RTC_getPrediv((int8_t*)&(RtcHandle.Init.AsynchPrediv), (int16_t*)&(RtcHandle.Init.SynchPrediv));
276334
#if defined(STM32L0xx) || defined(STM32L4xx)
277335
RtcHandle.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
278336
#endif // defined(STM32L0xx) || defined(STM32L4xx)

cores/arduino/stm32/rtc.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,14 @@ typedef void(*voidCallbackPtr)(void *);
8585

8686
#define HSE_RTC_MAX 1000000U
8787

88+
#if !defined(STM32F1xx)
89+
#if !defined(RTC_PRER_PREDIV_S) || !defined(RTC_PRER_PREDIV_S)
90+
#error "Unknown Family - unknown synchronous prescaler"
91+
#endif
92+
#define PREDIVA_MAX (RTC_PRER_PREDIV_A >> RTC_PRER_PREDIV_A_Pos)
93+
#define PREDIVS_MAX (RTC_PRER_PREDIV_S >> RTC_PRER_PREDIV_S_Pos)
94+
#endif /* !STM32F1xx */
95+
8896
/* Ultra Low Power High (ULPH) density */
8997
#if defined(STM32L100xBA) || defined (STM32L151xBA) || defined (STM32L152xBA) ||\
9098
defined(STM32L100xC) || defined (STM32L151xC) || defined (STM32L152xC) ||\
@@ -127,7 +135,10 @@ static uint32_t RTC_getSource(void) {
127135

128136
/* Exported macro ------------------------------------------------------------*/
129137
/* Exported functions ------------------------------------------------------- */
130-
void RTC_setPrediv(int8_t Asynch, int16_t Synch);
138+
void RTC_SetClockSource(sourceClock_t source);
139+
140+
void RTC_getPrediv(int8_t *asynch, int16_t *synch);
141+
void RTC_setPrediv(int8_t asynch, int16_t synch);
131142

132143
void RTC_init(hourFormat_t format, sourceClock_t source);
133144
void RTC_DeInit(void);

0 commit comments

Comments
 (0)