From ef205d218a71697234f1b523d4664357d2522085 Mon Sep 17 00:00:00 2001 From: Polprzewodnikowy Date: Wed, 8 Sep 2021 01:11:34 +0200 Subject: [PATCH] joybus rtc fully working with writes --- fw/rtl/n64/n64_flashram.sv | 2 +- sw/riscv/src/controller.c | 155 +++++++++++++++++++++++++++++++++---- sw/riscv/src/controller.h | 5 ++ sw/riscv/src/driver.c | 45 ++++++++++- sw/riscv/src/driver.h | 23 +++++- sw/riscv/src/handlers.c | 2 +- sw/riscv/src/sys.h | 4 + 7 files changed, 215 insertions(+), 21 deletions(-) diff --git a/fw/rtl/n64/n64_flashram.sv b/fw/rtl/n64/n64_flashram.sv index dc76434..4e8741d 100644 --- a/fw/rtl/n64/n64_flashram.sv +++ b/fw/rtl/n64/n64_flashram.sv @@ -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 diff --git a/sw/riscv/src/controller.c b/sw/riscv/src/controller.c index 05e47a2..b9e9656 100644 --- a/sw/riscv/src/controller.c +++ b/sw/riscv/src/controller.c @@ -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"); + } } } diff --git a/sw/riscv/src/controller.h b/sw/riscv/src/controller.h index 9064594..d5d4228 100644 --- a/sw/riscv/src/controller.h +++ b/sw/riscv/src/controller.h @@ -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, diff --git a/sw/riscv/src/driver.c b/sw/riscv/src/driver.c index fcfc524..94a3e65 100644 --- a/sw/riscv/src/driver.c +++ b/sw/riscv/src/driver.c @@ -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' }; diff --git a/sw/riscv/src/driver.h b/sw/riscv/src/driver.h index ee50e47..9c411a1 100644 --- a/sw/riscv/src/driver.h +++ b/sw/riscv/src/driver.h @@ -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); diff --git a/sw/riscv/src/handlers.c b/sw/riscv/src/handlers.c index 36f0c45..369d7da 100644 --- a/sw/riscv/src/handlers.c +++ b/sw/riscv/src/handlers.c @@ -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) diff --git a/sw/riscv/src/sys.h b/sw/riscv/src/sys.h index 5a5e570..21e1367 100644 --- a/sw/riscv/src/sys.h +++ b/sw/riscv/src/sys.h @@ -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