#include "DS3231.h" #define DS3231_I2C_ADDR (0x68U << 1) #define DS3231_REG_SECONDS 0x00U #define DS3231_REG_ALARM1 0x07U #define DS3231_REG_CONTROL 0x0EU #define DS3231_REG_STATUS 0x0FU #define DS3231_I2C_TIMEOUT_MS 200U #define DS3231_CONTROL_EOSC 0x80U #define DS3231_CONTROL_BBSQW 0x40U #define DS3231_CONTROL_CONV 0x20U #define DS3231_CONTROL_INTCN 0x04U #define DS3231_CONTROL_A2IE 0x02U #define DS3231_CONTROL_A1IE 0x01U #define DS3231_STATUS_OSF 0x80U #define DS3231_STATUS_EN32KHZ 0x08U #define DS3231_STATUS_A2F 0x02U #define DS3231_STATUS_A1F 0x01U static I2C_HandleTypeDef *ds3231_i2c = 0; volatile uint8_t ds3231_last_control = 0U; volatile uint8_t ds3231_last_status = 0U; volatile uint8_t ds3231_last_error = 0U; static uint8_t DS3231_DecToBcd(uint8_t value) { return (uint8_t)(((value / 10U) << 4) | (value % 10U)); } static uint8_t DS3231_BcdToDec(uint8_t value) { return (uint8_t)(((value >> 4) * 10U) + (value & 0x0FU)); } static uint8_t DS3231_WriteReg(uint8_t reg, uint8_t value) { if (ds3231_i2c == 0) { ds3231_last_error = 1U; return 0U; } if (HAL_I2C_Mem_Write(ds3231_i2c, DS3231_I2C_ADDR, reg, I2C_MEMADD_SIZE_8BIT, &value, 1U, DS3231_I2C_TIMEOUT_MS) != HAL_OK) { ds3231_last_error = 2U; return 0U; } ds3231_last_error = 0U; return 1U; } static uint8_t DS3231_ReadReg(uint8_t reg, uint8_t *value) { if ((ds3231_i2c == 0) || (value == 0)) { ds3231_last_error = 3U; return 0U; } if (HAL_I2C_Mem_Read(ds3231_i2c, DS3231_I2C_ADDR, reg, I2C_MEMADD_SIZE_8BIT, value, 1U, DS3231_I2C_TIMEOUT_MS) != HAL_OK) { ds3231_last_error = 4U; return 0U; } ds3231_last_error = 0U; return 1U; } uint8_t DS3231_Init(I2C_HandleTypeDef *hi2c) { ds3231_i2c = hi2c; return (ds3231_i2c != 0) ? 1U : 0U; } uint8_t DS3231_SetDateTime(const DS3231_DateTime_t *dateTime) { uint8_t buf[7]; if ((ds3231_i2c == 0) || (dateTime == 0)) { return 0U; } buf[0] = DS3231_DecToBcd(dateTime->second); buf[1] = DS3231_DecToBcd(dateTime->minute); buf[2] = DS3231_DecToBcd(dateTime->hour); buf[3] = DS3231_DecToBcd(dateTime->day); buf[4] = DS3231_DecToBcd(dateTime->date); buf[5] = DS3231_DecToBcd(dateTime->month); buf[6] = DS3231_DecToBcd(dateTime->year); return (HAL_I2C_Mem_Write(ds3231_i2c, DS3231_I2C_ADDR, DS3231_REG_SECONDS, I2C_MEMADD_SIZE_8BIT, buf, sizeof(buf), DS3231_I2C_TIMEOUT_MS) == HAL_OK) ? 1U : 0U; } static uint8_t DS3231_ReadDateTime(DS3231_DateTime_t *dateTime) { uint8_t buf[7]; if ((ds3231_i2c == 0) || (dateTime == 0)) { return 0U; } if (HAL_I2C_Mem_Read(ds3231_i2c, DS3231_I2C_ADDR, DS3231_REG_SECONDS, I2C_MEMADD_SIZE_8BIT, buf, sizeof(buf), DS3231_I2C_TIMEOUT_MS) != HAL_OK) { ds3231_last_error = 5U; return 0U; } dateTime->second = DS3231_BcdToDec((uint8_t)(buf[0] & 0x7FU)); dateTime->minute = DS3231_BcdToDec((uint8_t)(buf[1] & 0x7FU)); dateTime->hour = DS3231_BcdToDec((uint8_t)(buf[2] & 0x3FU)); dateTime->day = DS3231_BcdToDec((uint8_t)(buf[3] & 0x07U)); dateTime->date = DS3231_BcdToDec((uint8_t)(buf[4] & 0x3FU)); dateTime->month = DS3231_BcdToDec((uint8_t)(buf[5] & 0x1FU)); dateTime->year = DS3231_BcdToDec(buf[6]); ds3231_last_error = 0U; return 1U; } uint8_t DS3231_ClearAlarm1(void) { uint8_t status; if (DS3231_ReadReg(DS3231_REG_STATUS, &status) == 0U) { return 0U; } status &= (uint8_t)~(DS3231_STATUS_A1F | DS3231_STATUS_A2F); ds3231_last_status = status; return DS3231_WriteReg(DS3231_REG_STATUS, status); } uint8_t DS3231_ConfigAlarm1EveryMinute(void) { uint8_t alarm1[4] = { DS3231_DecToBcd(0U), 0x80U, 0x80U, 0x80U }; uint8_t control; uint8_t status; if (ds3231_i2c == 0) { return 0U; } if (HAL_I2C_Mem_Write(ds3231_i2c, DS3231_I2C_ADDR, DS3231_REG_ALARM1, I2C_MEMADD_SIZE_8BIT, alarm1, sizeof(alarm1), DS3231_I2C_TIMEOUT_MS) != HAL_OK) { return 0U; } if (DS3231_ReadReg(DS3231_REG_CONTROL, &control) == 0U) { return 0U; } control &= (uint8_t)~(DS3231_CONTROL_EOSC | DS3231_CONTROL_CONV | DS3231_CONTROL_A2IE); control |= (uint8_t)(DS3231_CONTROL_BBSQW | DS3231_CONTROL_INTCN | DS3231_CONTROL_A1IE); ds3231_last_control = control; if (DS3231_WriteReg(DS3231_REG_CONTROL, control) == 0U) { return 0U; } if (DS3231_ReadReg(DS3231_REG_STATUS, &status) == 0U) { return 0U; } status &= (uint8_t)~(DS3231_STATUS_A1F | DS3231_STATUS_A2F | DS3231_STATUS_OSF); ds3231_last_status = status; return DS3231_WriteReg(DS3231_REG_STATUS, status); } uint8_t DS3231_ConfigAlarm1AfterMinutes(uint8_t minutesFromNow) { DS3231_DateTime_t now; uint8_t alarm1[4]; uint8_t control; uint8_t status; uint16_t currentMinuteTotal; uint16_t nextMinuteTotal; uint8_t nextHour; uint8_t nextMinute; if ((ds3231_i2c == 0) || (minutesFromNow == 0U)) { return 0U; } if (DS3231_ReadDateTime(&now) == 0U) { return 0U; } /* * Align every node to the same wall-clock boundary. For 240 minutes, * alarms occur at 00:00, 04:00, 08:00, 12:00, 16:00 and 20:00, * independent of how long each relay node needed to forward its queue. */ currentMinuteTotal = (uint16_t)(((uint16_t)now.hour * 60U) + now.minute); nextMinuteTotal = (uint16_t)(((currentMinuteTotal / minutesFromNow) + 1U) * minutesFromNow); if (nextMinuteTotal >= (24U * 60U)) { nextMinuteTotal %= (24U * 60U); } nextHour = (uint8_t)(nextMinuteTotal / 60U); nextMinute = (uint8_t)(nextMinuteTotal % 60U); alarm1[0] = DS3231_DecToBcd(0U); alarm1[1] = DS3231_DecToBcd(nextMinute); alarm1[2] = DS3231_DecToBcd(nextHour); alarm1[3] = 0x80U; if (HAL_I2C_Mem_Write(ds3231_i2c, DS3231_I2C_ADDR, DS3231_REG_ALARM1, I2C_MEMADD_SIZE_8BIT, alarm1, sizeof(alarm1), DS3231_I2C_TIMEOUT_MS) != HAL_OK) { ds3231_last_error = 6U; return 0U; } if (DS3231_ReadReg(DS3231_REG_CONTROL, &control) == 0U) { return 0U; } control &= (uint8_t)~(DS3231_CONTROL_EOSC | DS3231_CONTROL_CONV | DS3231_CONTROL_A2IE); control |= (uint8_t)(DS3231_CONTROL_BBSQW | DS3231_CONTROL_INTCN | DS3231_CONTROL_A1IE); ds3231_last_control = control; if (DS3231_WriteReg(DS3231_REG_CONTROL, control) == 0U) { return 0U; } if (DS3231_ReadReg(DS3231_REG_STATUS, &status) == 0U) { return 0U; } status &= (uint8_t)~(DS3231_STATUS_A1F | DS3231_STATUS_A2F | DS3231_STATUS_OSF); ds3231_last_status = status; return DS3231_WriteReg(DS3231_REG_STATUS, status); }