mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 05:59:15 +01:00
joybus rtc fully working with writes
This commit is contained in:
parent
3ab5b7b6c8
commit
ef205d218a
@ -60,7 +60,7 @@ module n64_flashram (
|
||||
if (write_buffer_wmask[0]) high_buffer <= bus.wdata;
|
||||
end
|
||||
|
||||
always @(posedge sys.clk) begin
|
||||
always_ff @(posedge sys.clk) begin
|
||||
flashram.rdata <= write_buffer[flashram.address];
|
||||
if (write_buffer_wmask[1]) write_buffer[bus.address[6:2]] <= {high_buffer, bus.wdata};
|
||||
end
|
||||
|
@ -30,6 +30,7 @@ void process_cfg (void);
|
||||
void process_flashram (void);
|
||||
void process_si (void);
|
||||
void process_rtc (void);
|
||||
void process_uart (void);
|
||||
|
||||
|
||||
bool debug_decide (uint32_t *args);
|
||||
@ -45,19 +46,14 @@ void main (void) {
|
||||
usb_flush_rx();
|
||||
usb_flush_tx();
|
||||
si_reset();
|
||||
i2c_stop();
|
||||
|
||||
cfg_set_sdram_switch(true);
|
||||
cfg_set_save_type(CFG_SAVE_TYPE_NONE);
|
||||
cfg_set_dd_offset(CFG_DEFAULT_DD_OFFSET);
|
||||
cfg_set_cpu_ready(true);
|
||||
|
||||
current_time[0] = 0x10;
|
||||
current_time[1] = 0x30;
|
||||
current_time[2] = 0x90;
|
||||
current_time[3] = 0x06;
|
||||
current_time[4] = 0x01;
|
||||
current_time[5] = 0x09;
|
||||
current_time[6] = 0x21;
|
||||
print("App ready!\r\n");
|
||||
|
||||
while (1) {
|
||||
process_usb();
|
||||
@ -65,6 +61,7 @@ void main (void) {
|
||||
process_flashram();
|
||||
process_si();
|
||||
process_rtc();
|
||||
process_uart();
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,7 +235,7 @@ void process_flashram (void) {
|
||||
}
|
||||
|
||||
void process_si (void) {
|
||||
uint8_t rx_data[12];
|
||||
uint8_t rx_data[10];
|
||||
uint8_t tx_data[12];
|
||||
uint32_t *save_data;
|
||||
uint32_t *data_offset;
|
||||
@ -288,13 +285,10 @@ void process_si (void) {
|
||||
if (!rtc_running) {
|
||||
tx_data[1] = SI_RTC_ST_MASK;
|
||||
}
|
||||
} else if (rx_data[1] == 1) {
|
||||
// Backup SRAM
|
||||
} else {
|
||||
} else if (rx_data[1] == 2) {
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
tx_data[i] = current_time[i];
|
||||
}
|
||||
tx_data[2] |= 0x80;
|
||||
tx_data[7] = SI_RTC_CENTURY_20XX;
|
||||
}
|
||||
tx_data[8] = SI_RTC_STATUS(rtc_running);
|
||||
@ -305,9 +299,7 @@ void process_si (void) {
|
||||
if (rx_data[1] == 0) {
|
||||
rtc_wp_bits = rx_data[2] & SI_RTC_WP_MASK;
|
||||
rtc_running = (!(rx_data[3] & SI_RTC_ST_MASK));
|
||||
} else if (rx_data[1] == 1) {
|
||||
// Backup SRAM
|
||||
} else {
|
||||
} else if (rx_data[1] == 2) {
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
new_time[i] = rx_data[i + 2];
|
||||
}
|
||||
@ -324,11 +316,142 @@ void process_si (void) {
|
||||
}
|
||||
|
||||
void process_rtc (void) {
|
||||
static e_rtc_state_t state = RTC_STATE_READ;
|
||||
static e_rtc_state_t next_state = RTC_STATE_READ;
|
||||
static uint8_t phase = 0;
|
||||
static uint8_t sub_phase = 0;
|
||||
static uint8_t rtc_current_time[7];
|
||||
static uint8_t rtc_new_time[7];
|
||||
|
||||
if (new_time_pending) {
|
||||
new_time_pending = false;
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
current_time[i] = new_time[i];
|
||||
}
|
||||
new_time_pending = false;
|
||||
|
||||
rtc_convert_from_n64(new_time, rtc_new_time);
|
||||
|
||||
rtc_new_time[RTC_RTCSEC] |= RTC_RTCSEC_ST;
|
||||
rtc_new_time[RTC_RTCWKDAY] |= RTC_RTCWKDAY_VBAT;
|
||||
|
||||
next_state = RTC_STATE_WRITE;
|
||||
}
|
||||
|
||||
// TODO: Rewrite this mess
|
||||
if (!i2c_busy()) {
|
||||
if (state == RTC_STATE_READ) {
|
||||
switch (phase) {
|
||||
case 0: phase++; i2c_start(); break;
|
||||
case 1: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 2: phase++; i2c_begin_trx(RTC_RTCSEC, false); break;
|
||||
case 3: phase++; i2c_start(); break;
|
||||
case 4: phase++; i2c_begin_trx(RTC_ADDR | I2C_ADDR_READ, false); break;
|
||||
case 5:
|
||||
if (sub_phase > 0) {
|
||||
rtc_current_time[sub_phase - 1] = i2c_get_data();
|
||||
}
|
||||
if (sub_phase < 7) {
|
||||
i2c_begin_trx(0xFF, true);
|
||||
}
|
||||
if (sub_phase == 7) {
|
||||
phase++;
|
||||
sub_phase = 0;
|
||||
if (next_state != RTC_STATE_WRITE) {
|
||||
rtc_convert_to_n64(rtc_current_time, current_time);
|
||||
}
|
||||
break;
|
||||
}
|
||||
sub_phase++;
|
||||
break;
|
||||
case 6: phase = 0; i2c_stop(); state = next_state; break;
|
||||
}
|
||||
} else if (state == RTC_STATE_WRITE) {
|
||||
switch (phase) {
|
||||
case 0: phase++; break;
|
||||
|
||||
case 1: phase++; i2c_start(); break;
|
||||
case 2: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 3: phase++; i2c_begin_trx(RTC_RTCSEC, false); break;
|
||||
case 4: phase++; i2c_begin_trx(0x00, false); break;
|
||||
case 5: phase++; i2c_stop(); break;
|
||||
|
||||
case 6: phase++; i2c_start(); break;
|
||||
case 7: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 8: phase++; i2c_begin_trx(RTC_RTCWKDAY, false); break;
|
||||
case 9: phase++; i2c_start(); break;
|
||||
case 10: phase++; i2c_begin_trx(RTC_ADDR | I2C_ADDR_READ, false); break;
|
||||
case 11: phase++; i2c_begin_trx(0xFF, false); break;
|
||||
case 12: phase = (i2c_get_data() & RTC_RTCWKDAY_OSCRUN) ? 6 : 13; i2c_stop(); break;
|
||||
|
||||
case 13: phase++; i2c_start(); break;
|
||||
case 14: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 15: phase++; i2c_begin_trx(RTC_RTCMIN, false); break;
|
||||
case 16:
|
||||
if (sub_phase < 6) {
|
||||
i2c_begin_trx(rtc_new_time[RTC_RTCMIN + sub_phase], false);
|
||||
sub_phase++;
|
||||
} else {
|
||||
phase++;
|
||||
sub_phase = 0;
|
||||
i2c_stop();
|
||||
}
|
||||
break;
|
||||
|
||||
case 17: phase++; i2c_start(); break;
|
||||
case 18: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 19: phase++; i2c_begin_trx(RTC_RTCSEC, false); break;
|
||||
case 20: phase++; i2c_begin_trx(rtc_new_time[RTC_RTCSEC], false); break;
|
||||
case 21: phase++; i2c_stop(); break;
|
||||
|
||||
case 22: phase++; i2c_start(); break;
|
||||
case 23: phase++; i2c_begin_trx(RTC_ADDR, false); break;
|
||||
case 24: phase++; i2c_begin_trx(RTC_RTCWKDAY, false); break;
|
||||
case 25: phase++; i2c_start(); break;
|
||||
case 26: phase++; i2c_begin_trx(RTC_ADDR | I2C_ADDR_READ, false); break;
|
||||
case 27: phase++; i2c_begin_trx(0xFF, false); break;
|
||||
case 28:
|
||||
if (i2c_get_data() & RTC_RTCWKDAY_OSCRUN) {
|
||||
phase = 0;
|
||||
state = RTC_STATE_READ;
|
||||
next_state = RTC_STATE_READ;
|
||||
} else {
|
||||
phase = 22;
|
||||
}
|
||||
i2c_stop();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
state = RTC_STATE_READ;
|
||||
phase = 0;
|
||||
sub_phase = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process_uart (void) {
|
||||
if (UART->SCR & USB_SCR_RXNE) {
|
||||
char cmd = UART->DR;
|
||||
|
||||
switch (cmd) {
|
||||
case '/':
|
||||
print("Bootloader reset...\r\n");
|
||||
reset_handler();
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
print("App reset...\r\n");
|
||||
app_handler();
|
||||
break;
|
||||
|
||||
case 't':
|
||||
print("Current time: ");
|
||||
for (int i = 0; i < 7; i++) {
|
||||
print_02hex(current_time[i]);
|
||||
print(" ");
|
||||
}
|
||||
print("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,11 @@ typedef enum {
|
||||
USB_STATE_PC_TO_N64,
|
||||
} e_usb_state_t;
|
||||
|
||||
typedef enum {
|
||||
RTC_STATE_READ,
|
||||
RTC_STATE_WRITE,
|
||||
} e_rtc_state_t;
|
||||
|
||||
typedef enum {
|
||||
DEBUG_WRITE_ADDRESS,
|
||||
DEBUG_WRITE_LENGTH_START,
|
||||
|
@ -323,9 +323,50 @@ uint8_t i2c_get_data (void) {
|
||||
}
|
||||
|
||||
|
||||
// misc
|
||||
// RTC
|
||||
|
||||
const char hex_char_map[16] = {
|
||||
static const uint8_t rtc_bit_mask[7] = {
|
||||
0b01111111,
|
||||
0b01111111,
|
||||
0b00111111,
|
||||
0b00000111,
|
||||
0b00111111,
|
||||
0b00011111,
|
||||
0b11111111
|
||||
};
|
||||
|
||||
void rtc_sanitize_time_data (uint8_t *time_data) {
|
||||
for (int i = 0; i < 7; i++) {
|
||||
time_data[i] &= rtc_bit_mask[i];
|
||||
}
|
||||
}
|
||||
|
||||
void rtc_convert_to_n64 (uint8_t *rtc_data, uint8_t *n64_data) {
|
||||
rtc_sanitize_time_data(rtc_data);
|
||||
n64_data[0] = rtc_data[RTC_RTCSEC];
|
||||
n64_data[1] = rtc_data[RTC_RTCMIN];
|
||||
n64_data[2] = rtc_data[RTC_RTCHOUR] | 0x80;
|
||||
n64_data[4] = rtc_data[RTC_RTCWKDAY] - 1;
|
||||
n64_data[3] = rtc_data[RTC_RTCDATE];
|
||||
n64_data[5] = rtc_data[RTC_RTCMTH];
|
||||
n64_data[6] = rtc_data[RTC_RTCYEAR];
|
||||
}
|
||||
|
||||
void rtc_convert_from_n64 (uint8_t *n64_data, uint8_t *rtc_data) {
|
||||
rtc_data[RTC_RTCSEC] = n64_data[0];
|
||||
rtc_data[RTC_RTCMIN] = n64_data[1];
|
||||
rtc_data[RTC_RTCHOUR] = n64_data[2];
|
||||
rtc_data[RTC_RTCWKDAY] = n64_data[4] + 1;
|
||||
rtc_data[RTC_RTCDATE] = n64_data[3];
|
||||
rtc_data[RTC_RTCMTH] = n64_data[5];
|
||||
rtc_data[RTC_RTCYEAR] = n64_data[6];
|
||||
rtc_sanitize_time_data(rtc_data);
|
||||
}
|
||||
|
||||
|
||||
// Misc
|
||||
|
||||
static const char hex_char_map[16] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
|
@ -133,7 +133,28 @@ void i2c_begin_trx (uint8_t data, bool mack);
|
||||
uint8_t i2c_get_data (void);
|
||||
|
||||
|
||||
// misc
|
||||
// RTC
|
||||
|
||||
#define RTC_ADDR (0xDE)
|
||||
|
||||
#define RTC_RTCSEC (0x00)
|
||||
#define RTC_RTCMIN (0x01)
|
||||
#define RTC_RTCHOUR (0x02)
|
||||
#define RTC_RTCWKDAY (0x03)
|
||||
#define RTC_RTCDATE (0x04)
|
||||
#define RTC_RTCMTH (0x05)
|
||||
#define RTC_RTCYEAR (0x06)
|
||||
|
||||
#define RTC_RTCSEC_ST (1 << 7)
|
||||
#define RTC_RTCWKDAY_OSCRUN (1 << 5)
|
||||
#define RTC_RTCWKDAY_VBAT (1 << 3)
|
||||
|
||||
void rtc_sanitize_time_data(uint8_t *time_data);
|
||||
void rtc_convert_to_n64 (uint8_t *rtc_data, uint8_t *n64_data);
|
||||
void rtc_convert_from_n64 (uint8_t *n64_data, uint8_t *rtc_data);
|
||||
|
||||
|
||||
// Misc
|
||||
|
||||
void print (const char *text);
|
||||
void print_02hex (uint8_t number);
|
||||
|
@ -5,7 +5,7 @@
|
||||
#define BOOT_UART
|
||||
|
||||
|
||||
__attribute__ ((naked, section(".bootloader"))) int reset_handler (void) {
|
||||
__attribute__ ((naked, section(".bootloader"))) void reset_handler (void) {
|
||||
register uint32_t length = 0;
|
||||
|
||||
#if defined(BOOT_UART)
|
||||
|
@ -156,4 +156,8 @@ typedef volatile struct si_regs {
|
||||
#define SI_SCR_TX_LENGTH_BIT (16)
|
||||
|
||||
|
||||
void reset_handler (void);
|
||||
void app_handler (void);
|
||||
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user