SummerCart64/fw/cpu/controller/rtc.c
Polprzewodnikowy b1826a9167 goot
2021-08-23 22:30:47 +02:00

129 lines
2.7 KiB
C

#include "sys.h"
#include "rtc.h"
static const uint8_t rtc_bit_mask[7] = {
0b01111111,
0b01111111,
0b00111111,
0b00000111,
0b00111111,
0b00011111,
0b11111111
};
static uint8_t i2c_is_busy (void) {
return (I2C_SR & I2C_SR_BUSY);
}
static void i2c_wait_busy (void) {
while (i2c_is_busy());
}
static uint8_t i2c_has_ack (void) {
return (I2C_SR & I2C_SR_ACK);
}
static void i2c_start (void) {
i2c_wait_busy();
I2C_SR = I2C_SR_START;
}
static void i2c_stop (void) {
i2c_wait_busy();
I2C_SR = I2C_SR_STOP;
}
static uint8_t i2c_write (uint8_t data) {
i2c_wait_busy();
I2C_SR = 0;
I2C_DR = data;
i2c_wait_busy();
return i2c_has_ack();
}
static void i2c_read (uint8_t *data, uint8_t cfg) {
i2c_wait_busy();
I2C_SR = cfg;
I2C_DR = 0xFF;
i2c_wait_busy();
*data = I2C_DR;
}
static uint8_t i2c_tx (uint8_t address, uint8_t *data, size_t length) {
uint8_t result = 0;
i2c_start();
result |= i2c_write(RTC_ADDR);
result |= i2c_write(address);
for (size_t i = 0; i < length; i++) {
result |= i2c_write(*data++);
}
i2c_stop();
return result;
}
static uint8_t i2c_rx (uint8_t address, uint8_t *data, size_t length) {
uint8_t result = 0;
i2c_start();
result |= i2c_write(RTC_ADDR);
result |= i2c_write(address);
i2c_start();
result |= i2c_write(RTC_ADDR | I2C_ADDR_READ);
for (size_t i = 0; i < length; i++) {
i2c_read(data++, (i == (length - 1)) ? 0 : I2C_SR_MACK);
}
i2c_stop();
return result;
}
static void rtc_sanitize_data (uint8_t *rtc_data) {
for (int i = 0; i < 7; i++) {
rtc_data[i] &= rtc_bit_mask[i];
}
}
uint8_t rtc_set_time (uint8_t *rtc_data) {
uint8_t result = 0;
uint8_t tmp;
rtc_sanitize_data(rtc_data);
rtc_data[RTC_RTCSEC] |= RTC_RTCSEC_ST;
rtc_data[RTC_RTCWKDAY] |= RTC_RTCWKDAY_VBAT;
result |= i2c_tx(RTC_RTCSEC, 0x00, 1);
result |= i2c_tx(RTC_RTCMIN, rtc_data + 1, 6);
result |= i2c_tx(RTC_RTCSEC, rtc_data, 1);
do {
result |= i2c_rx(RTC_RTCWKDAY, &tmp, 7);
} while ((!(tmp & RTC_RTCWKDAY_OSCRUN)) || !result);
return result;
}
uint8_t rtc_get_time (uint8_t *rtc_data) {
uint8_t result = i2c_rx(RTC_RTCSEC, rtc_data, 7);
rtc_sanitize_data(rtc_data);
return result;
}
void rtc_init (void) {
uint8_t result;
uint8_t rtc_data[7];
result = i2c_rx(RTC_RTCSEC, rtc_data, 1);
if ((!(rtc_data[0] & RTC_RTCSEC_ST)) && (!result)) {
rtc_get_time(rtc_data);
rtc_set_time(rtc_data);
}
}