mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-27 08:04:14 +01:00
129 lines
2.7 KiB
C
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);
|
|
}
|
|
}
|