44#define ANSI_HIDE_CURSOR "\x1b[?25l"
50#define FORCE_SET_TIME 0
54#define SET_TIME_OFFSET_SECONDS 0
65#define CLOCK_MARKER_ADDRESS 0U
68#define CLOCK_MARKER_MAGIC 0x44533332U
71#define CLOCK_MARKER_SIZE 8U
84I2C_HandleTypeDef hi2c1;
86UART_HandleTypeDef huart1;
98 "",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
104 "",
"January",
"February",
"March",
"April",
"May",
"June",
105 "July",
"August",
"September",
"October",
"November",
"December"
110void SystemClock_Config(
void);
111static void MX_GPIO_Init(
void);
112static void MX_I2C1_Init(
void);
113static void MX_USART1_UART_Init(
void);
127#ifdef REDIRECT_PRINTF
128#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
132 HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
161 SystemClock_Config();
170 MX_USART1_UART_Init();
173 printf(
"\x1b[2J\x1b[H");
175 printf(
"\x1b[1mDS3231 real-time clock\x1b[0m\r\n-----------------------\r\n\r\n");
179 printf(
"DS3231 not found on I2C1 (HAL status %d, I2C error 0x%02lX)\r\n",
180 (
int)
rtc.
lastStatus, (
unsigned long)HAL_I2C_GetError(&hi2c1));
185 printf(
"AT24C32 EEPROM not found on I2C1 (HAL status %d, I2C error 0x%02lX)\r\n",
211void SystemClock_Config(
void)
213 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
214 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
218 HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
222 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
224 while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
229 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
230 RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
231 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
232 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
233 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
234 RCC_OscInitStruct.PLL.PLLM = 4;
235 RCC_OscInitStruct.PLL.PLLN = 60;
236 RCC_OscInitStruct.PLL.PLLP = 2;
237 RCC_OscInitStruct.PLL.PLLQ = 4;
238 RCC_OscInitStruct.PLL.PLLR = 2;
239 RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
240 RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
241 RCC_OscInitStruct.PLL.PLLFRACN = 0;
242 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
249 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
250 |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
251 |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
252 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
253 RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
254 RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
255 RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
256 RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
257 RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
258 RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
260 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
271static void MX_I2C1_Init(
void)
281 hi2c1.Instance = I2C1;
282 hi2c1.Init.Timing = 0x307075B1;
283 hi2c1.Init.OwnAddress1 = 0;
284 hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
285 hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
286 hi2c1.Init.OwnAddress2 = 0;
287 hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
288 hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
289 hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
290 if (HAL_I2C_Init(&hi2c1) != HAL_OK)
297 if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
304 if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
319static void MX_USART1_UART_Init(
void)
329 huart1.Instance = USART1;
330 huart1.Init.BaudRate = 19200;
331 huart1.Init.WordLength = UART_WORDLENGTH_8B;
332 huart1.Init.StopBits = UART_STOPBITS_1;
333 huart1.Init.Parity = UART_PARITY_NONE;
334 huart1.Init.Mode = UART_MODE_TX_RX;
335 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
336 huart1.Init.OverSampling = UART_OVERSAMPLING_16;
337 huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
338 huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
339 huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
340 if (HAL_UART_Init(&huart1) != HAL_OK)
344 if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
348 if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
352 if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
367static void MX_GPIO_Init(
void)
369 GPIO_InitTypeDef GPIO_InitStruct = {0};
375 __HAL_RCC_GPIOC_CLK_ENABLE();
376 __HAL_RCC_GPIOH_CLK_ENABLE();
377 __HAL_RCC_GPIOD_CLK_ENABLE();
378 __HAL_RCC_GPIOA_CLK_ENABLE();
379 __HAL_RCC_GPIOB_CLK_ENABLE();
382 GPIO_InitStruct.Pin = STLINK_RX_Pin|STLINK_TX_Pin;
383 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
384 GPIO_InitStruct.Pull = GPIO_NOPULL;
385 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
386 GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
387 HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
403void _Error_Handler(
const char *file,
int line)
407#ifdef REDIRECT_PRINTF
410 snprintf(buf,
sizeof(buf),
411 "Trapped in _Error_Handler(). Called from: %s, line: %d\r\n",
433 bool stopped =
false;
436 printf(
"Could not read the DS3231 status register\r\n");
442 printf(
"Oscillator : stop flag SET, the time is not valid until the clock is set\r\n");
444 printf(
"Oscillator : stop flag clear, the time is valid\r\n");
459 static const char months[] =
"JanFebMarAprMayJunJulAugSepOctNovDec";
460 const char *date = __DATE__;
461 const char *clock = __TIME__;
462 const char *found = NULL;
465 for (i = 0U; i < 12U; i++) {
466 if (strncmp(&months[i * 3U], date, 3U) == 0) {
467 found = &months[i * 3U];
468 time->
month = (uint8_t)(i + 1U);
475 time->
day = (uint8_t)(((date[4] ==
' ') ? 0 : (date[4] -
'0')) * 10 + (date[5] -
'0'));
476 time->
year = (uint16_t)((date[7] -
'0') * 1000 + (date[8] -
'0') * 100 + (date[9] -
'0') * 10 + (date[10] -
'0'));
477 time->
hour = (uint8_t)((clock[0] -
'0') * 10 + (clock[1] -
'0'));
478 time->
minute = (uint8_t)((clock[3] -
'0') * 10 + (clock[4] -
'0'));
479 time->
second = (uint8_t)((clock[6] -
'0') * 10 + (clock[7] -
'0'));
498 printf(
"The build time cannot be used to set the clock\r\n");
504 printf(
"Setting the DS3231 failed\r\n");
509 printf(
"Clock : set to the build time %04d-%02d-%02d %02d:%02d:%02d (offset %d s)\r\n",
528 printf(
"Could not read the clock marker from the EEPROM\r\n");
533 memcpy(&magic, &raw[0],
sizeof(magic));
534 memcpy(&inverse, &raw[4],
sizeof(inverse));
549 memcpy(&raw[0], &magic,
sizeof(magic));
550 memcpy(&raw[4], &inverse,
sizeof(inverse));
553 printf(
"Writing the clock marker to the EEPROM failed\r\n");
572 printf(
"EEPROM : FORCE_SET_TIME is 1, setting the clock\r\n");
573 }
else if (markerFound) {
574 printf(
"EEPROM : marker found, the clock was set before\r\n");
575 printf(
"Clock : left alone\r\n");
577 printf(
"Warning : the oscillator stopped since the clock was set.\r\n");
578 printf(
" Set FORCE_SET_TIME to 1 and rebuild to set it again.\r\n");
582 printf(
"EEPROM : no marker, first run on this board\r\n");
587 printf(
"EEPROM : marker written\r\n");
590 printf(
"Reminder : set FORCE_SET_TIME to 0 and rebuild, or every reset\r\n");
591 printf(
" sets the clock back to this build time.\r\n");
611 printf(
"\x1b[%d;1H\x1b[K The DS3231 does not hold a valid time yet\x1b[%d;1H\x1b[K",
CLOCK_ROW,
CLOCK_ROW + 1);
616 printf(
"ds3231GetTime failed, status %d\r\n", (
int)status);
622 printf(
"\x1b[%d;1H\x1b[K The DS3231 returned a date that cannot be named\x1b[%d;1H\x1b[K",
CLOCK_ROW,
CLOCK_ROW + 1);
627 printf(
"\x1b[%d;1H\x1b[K %s, %s %d, %04d\x1b[%d;1H\x1b[K \x1b[1m%02d:%02d:%02d\x1b[0m",
636#ifdef USE_FULL_ASSERT
644void assert_failed(uint8_t *file, uint32_t line)
655#ifdef REDIRECT_PRINTF
659 snprintf(buf,
sizeof(buf),
660 "assert_param failed: file %s, line %lu\r\n",
661 (
char *)file, (
unsigned long)line);
Types, constants and function prototypes of the STM32_AT24C32 driver.
AT24C32_Status_t at24c32Init(AT24C32_t *dev, I2C_HandleTypeDef *hi2c, uint8_t addressPins, uint8_t maxAttempts)
Set up a driver handle and check that an AT24C32 answers on the bus.
AT24C32_Status_t at24c32Read(AT24C32_t *dev, uint16_t memAddress, uint8_t *data, uint16_t length)
Read bytes from the memory.
AT24C32_Status_t at24c32Write(AT24C32_t *dev, uint16_t memAddress, const uint8_t *data, uint16_t length)
Write bytes to the memory.
Types, constants and function prototypes of the STM32_DS3231 driver.
DS3231_Status_t ds3231SetTime(DS3231_t *dev, const DS3231_TIME_t *time)
Set the date and time.
DS3231_Status_t ds3231TimeToEpoch(const DS3231_TIME_t *time, uint32_t *epochSeconds)
Convert a date and time to seconds since 1970-01-01 00:00:00 (UTC, no leap seconds).
DS3231_Status_t ds3231EpochToTime(uint32_t epochSeconds, DS3231_TIME_t *time)
Convert seconds since 1970-01-01 00:00:00 (UTC, no leap seconds) to a date and time.
@ DS3231_ERR_INVALID_DATA
DS3231_Status_t ds3231GetTime(DS3231_t *dev, DS3231_TIME_t *time)
Read the current date and time.
bool ds3231IsTimeValid(const DS3231_TIME_t *time)
Check that a date and time are valid for the DS3231.
DS3231_Status_t ds3231ClearOscillatorStopFlag(DS3231_t *dev)
Clear the oscillator stop flag.
DS3231_Status_t ds3231IsOscillatorStopped(DS3231_t *dev, bool *stopped)
Find out whether the oscillator has stopped since the flag was last cleared.
DS3231_Status_t ds3231Init(DS3231_t *dev, I2C_HandleTypeDef *hi2c, uint8_t maxAttempts)
Set up a driver handle and check that a DS3231 answers on the bus.
static bool parseBuildTime(DS3231_TIME_t *time)
Convert the compile date and time (DATE and TIME) to a DS3231_TIME_t.
static bool reportOscillator(void)
Report whether the DS3231 oscillator stop flag is set.
static void setClockFromBuildTime(void)
Set the DS3231 to the build time plus SET_TIME_OFFSET_SECONDS and clear the oscillator stop flag.
int main(void)
The application entry point.
#define CLOCK_MARKER_MAGIC
static const char *const dayNames[8]
#define CLOCK_MARKER_ADDRESS
static void startClock(void)
Decide at start-up whether to set the clock, and do it.
static bool readClockMarker(void)
Tell whether the EEPROM holds the "clock already set" marker.
static void writeClockMarker(void)
Store the "clock already set" marker in the EEPROM and read it back to check it.
#define CLOCK_MARKER_SIZE
static const char *const monthNames[13]
#define SET_TIME_OFFSET_SECONDS
static void printTime(void)
Read the DS3231 and redraw the day, date and time on two terminal lines, for example "Wednesday,...
: Header for main.c file. This file contains the common defines of the application.
HAL_StatusTypeDef lastStatus
A calendar date and time, always 24-hour clock.
HAL_StatusTypeDef lastStatus