From cdee81d3ff2a1105611796c89d5c2ac615a467cb Mon Sep 17 00:00:00 2001 From: JackCarterSmith Date: Sat, 7 Jun 2025 15:57:31 +0200 Subject: [PATCH] Registers tweaks Prepare for new registers structure used in v1 --- Core/Inc/hal_interface.h | 1 + Core/Inc/i2cs.h | 20 ++++ Core/Inc/regs.h | 59 +++++++---- Core/Inc/version.h | 2 +- Core/Src/hal_interface.c | 1 + Core/Src/i2cs.c | 221 +++++++++++++++++++++++++++++++++++++++ Core/Src/keyboard.c | 12 +-- Core/Src/main.c | 218 +------------------------------------- Core/Src/regs.c | 49 +++++---- README.md | 18 +++- 10 files changed, 334 insertions(+), 267 deletions(-) create mode 100644 Core/Inc/i2cs.h create mode 100644 Core/Src/i2cs.c diff --git a/Core/Inc/hal_interface.h b/Core/Inc/hal_interface.h index 3c441b3..cd19cb4 100644 --- a/Core/Inc/hal_interface.h +++ b/Core/Inc/hal_interface.h @@ -145,6 +145,7 @@ extern volatile uint32_t systicks_counter; extern volatile uint8_t pmu_irq; extern volatile uint8_t stop_mode_active; +extern volatile uint8_t rtc_reg_xor_events; extern volatile RTC_TimeTypeDef_u rtc_alarm_time; extern volatile RTC_DateTypeDef_u rtc_alarm_date; diff --git a/Core/Inc/i2cs.h b/Core/Inc/i2cs.h new file mode 100644 index 0000000..38f309e --- /dev/null +++ b/Core/Inc/i2cs.h @@ -0,0 +1,20 @@ +#include "stm32f1xx_hal.h" + + +#ifndef I2CS_H_ +#define I2CS_H_ + +#define I2CS_REARM_TIMEOUT 500 + + +enum i2cs_state { + //I2CS_STATE_HALT, + I2CS_STATE_IDLE, + I2CS_STATE_REG_REQUEST, + I2CS_STATE_REG_ANSWER +}; + +extern enum i2cs_state i2cs_state; +extern uint32_t i2cs_rearm_counter; + +#endif /* I2CS_H_ */ diff --git a/Core/Inc/regs.h b/Core/Inc/regs.h index fb57dc3..246c14a 100644 --- a/Core/Inc/regs.h +++ b/Core/Inc/regs.h @@ -8,7 +8,7 @@ enum reg_id { REG_ID_TYP = 0x00, //!< firmware type (0=official, others=custom) REG_ID_VER = 0x01, //!< fw version (7:4=Major, 3:0=Minor) #ifdef I2C_REGS_COMPAT - REG_ID_CFG = 0x02, // config + REG_ID_SYS_CFG = 0x02, // config REG_ID_INT = 0x03, // interrupt status REG_ID_KEY = 0x04, // key status REG_ID_BKL = 0x05, // backlight steps (0-9) @@ -27,31 +27,54 @@ enum reg_id { REG_ID_RTC_ALARM_DATE = 0x12, // RTC alarm date REG_ID_RTC_ALARM_TIME = 0x13, // RTC alarm time #else - REG_ID_CFG = 0x02, //!< config + // TODO: REG_ID_CFG_0 - 32b (RW) + REG_ID_SYS_CFG = 0x02, //!< config REG_ID_INT_CFG = 0x03, //!< IRQ config - REG_ID_INT = 0x04, //!< interrupt status - REG_ID_BKL = 0x05, //!< backlight steps (0-9) - REG_ID_BK2 = 0x06, //!< keyboard backlight (0-9) - REG_ID_DEB = 0x07, //!< debounce cfg (time in ms) - REG_ID_FRQ = 0x08, //!< poll freq cfg (time in ms) - REG_ID_PWR_CTRL = 0x09, //!< Power control (0: idle, 1: pico reset, 2: system reset, 3: reserved, 4: sleep, 5: full-shutdown) + REG_ID_PWR_CTRL = 0x04, //!< Power control (0: idle, 1: pico reset, 2: system reset, 3: reserved, 4: sleep, 5: full-shutdown) + REG_ID_RTC_CFG = 0x05, //!< RTC general config - REG_ID_RTC_CFG = 0x0A, //!< RTC general config - REG_ID_RTC_DATE = 0x0B, //!< RTC date - REG_ID_RTC_TIME = 0x0C, //!< RTC time - REG_ID_RTC_ALARM_DATE = 0x0D, //!< RTC alarm date - REG_ID_RTC_ALARM_TIME = 0x0E, //!< RTC alarm time + // TODO: REG_ID_CFG_1 - 32b (RW) + REG_ID_DEB = 0x06, //!< debounce cfg (time in ms) + REG_ID_FRQ = 0x07, //!< poll freq cfg (time in ms) + REG_ID_BKL = 0x08, //!< backlight steps (0-9) + REG_ID_BK2 = 0x09, //!< keyboard backlight (0-9) - REG_ID_KEY = 0x10, //!< key status - REG_ID_FIF = 0x11, //!< fifo - REG_ID_C64_MTX = 0x12, //!< read c64 matrix - REG_ID_C64_JS = 0x13, //!< joystick io bits + // TODO: REG_ID_RTC_DATE - 32b (RW) + REG_ID_RTC_DATE = 0x0A, //!< RTC date + // TODO: REG_ID_RTC_TIME - 32b (RW) + REG_ID_RTC_TIME = 0x0B, //!< RTC time + // TODO: REG_ID_RTC_ALARM_DATE - 32b (RW) + REG_ID_RTC_ALARM_DATE = 0x0C, //!< RTC alarm date + // TODO: REG_ID_RTC_ALARM_TIME - 32b (RW) + REG_ID_RTC_ALARM_TIME = 0x0D, //!< RTC alarm time - REG_ID_BAT = 0x30, //!< battery + // TODO: REG_ID_INT - 32b (RO) + REG_ID_INT = 0x10, //!< interrupt flags status + + // TODO: REG_ID_KBD - 32b (RO) + REG_ID_KEY = 0x14, //!< key status - 8b + REG_ID_C64_JS = 0x15, //!< joystick io bits - 8b + REG_ID_FIF = 0x16, //!< fifo - 16b + + // TODO: REG_ID_BAT - 32b (RO) + REG_ID_BAT = 0x18, //!< battery percentage - 16b + //REG_ID_BAT_RAW //!< battery voltage value in mV - 16b + + // TODO: REG_ID_C64_MTX_0 - 32b (RO) + REG_ID_C64_MTX = 0x1A, //!< read c64 matrix + // TODO: REG_ID_C64_MTX_1 - 32b (RO) + // TODO: REG_ID_C64_MTX_2 - 32b (RO) #endif REG_ID_LAST }; +#define REGS_GLOBAL_ENTRY() + +typedef struct { + const uint8_t addr; + uint8_t* value[]; +} REGS_GLOBAL_ENTRY; + #define CFG_OVERFLOW_ON (1 << 0) //When a FIFO overflow happens, should the new entry still be pushed, overwriting the oldest one. If 0 then new entry is lost. #define CFG_REPORT_MODS (1 << 6) // Should Alt, Sym and Shifts be reported as well #define CFG_USE_MODS (1 << 7) // Should Alt, Sym and Shifts modify the keys reported diff --git a/Core/Inc/version.h b/Core/Inc/version.h index d00bd95..3da894f 100644 --- a/Core/Inc/version.h +++ b/Core/Inc/version.h @@ -2,6 +2,6 @@ #define VERSION_H_ #define VERSION_MAJOR (0) -#define VERSION_MINOR (5) +#define VERSION_MINOR (6) #endif /* VERSION_H_ */ diff --git a/Core/Src/hal_interface.c b/Core/Src/hal_interface.c index 10c9a46..c80ea85 100644 --- a/Core/Src/hal_interface.c +++ b/Core/Src/hal_interface.c @@ -37,6 +37,7 @@ UART_HandleTypeDef huart1; UART_HandleTypeDef huart3; #endif +volatile uint8_t rtc_reg_xor_events = 0; volatile RTC_TimeTypeDef_u rtc_alarm_time = {.raw = 0x00000000}; volatile RTC_DateTypeDef_u rtc_alarm_date = {.raw = 0x00010101}; diff --git a/Core/Src/i2cs.c b/Core/Src/i2cs.c new file mode 100644 index 0000000..1449ef5 --- /dev/null +++ b/Core/Src/i2cs.c @@ -0,0 +1,221 @@ +#include "i2cs.h" + +#include "hal_interface.h" +#include "backlight.h" +#include "fifo.h" +#include "rtc.h" +#include "regs.h" + + +extern I2C_HandleTypeDef hi2c1; +extern I2C_HandleTypeDef hi2c2; + +extern RTC_HandleTypeDef hrtc; + +static uint8_t i2cs_r_buff[5]; +static volatile uint8_t i2cs_r_idx = 0; +static uint8_t i2cs_w_buff[10]; +static volatile uint8_t i2cs_w_idx = 0; +static volatile uint8_t i2cs_w_len = 0; + +enum i2cs_state i2cs_state = I2CS_STATE_IDLE; +uint32_t i2cs_rearm_counter = 0; + + +extern void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) { + if (hi2c == &hi2c1) { + // I2C slave addr match error detection + if (AddrMatchCode != 0x3E) // 0x1F << 1 + return; + + if (TransferDirection == I2C_DIRECTION_TRANSMIT) { + if (i2cs_state == I2CS_STATE_IDLE) { + i2cs_state = I2CS_STATE_REG_REQUEST; + + i2cs_r_idx = 0; + HAL_I2C_Slave_Sequential_Receive_IT(hi2c, i2cs_r_buff, 1, I2C_FIRST_FRAME); // This write the first received byte to i2cs_r_buff[0] + + i2cs_rearm_counter = uptime_ms(); + } + } + + if (TransferDirection == I2C_DIRECTION_RECEIVE) { + if (i2cs_state == I2CS_STATE_REG_REQUEST) { + const uint8_t is_write = (uint8_t)(i2cs_r_buff[0] & (1 << 7)); + const uint8_t reg = (uint8_t)(i2cs_r_buff[0] & ~(1 << 7)); + + i2cs_w_buff[0] = reg; + i2cs_w_len = 2; + + if (reg == REG_ID_BKL) { // We wait an another byte for these registers + if (is_write) + lcd_backlight_update(i2cs_r_buff[1]); + i2cs_w_buff[1] = reg_get_value(REG_ID_BKL); + } else if (reg == REG_ID_BK2) { + if (is_write) + kbd_backlight_update(i2cs_r_buff[1]); + i2cs_w_buff[1] = reg_get_value(REG_ID_BK2); + } else if (reg == REG_ID_SYS_CFG) { + if (is_write) + reg_set_value(REG_ID_SYS_CFG, i2cs_r_buff[1]); + i2cs_w_buff[1] = reg_get_value(REG_ID_SYS_CFG); + } else if (reg == REG_ID_INT_CFG) { + if (is_write) + reg_set_value(REG_ID_INT_CFG, i2cs_r_buff[1]); + i2cs_w_buff[1] = reg_get_value(REG_ID_INT_CFG); + } else if (reg == REG_ID_DEB) { + if (is_write) { + keyboard_set_hold_period(*((uint16_t*)&i2cs_r_buff[1])); + reg_set_value(REG_ID_DEB, 0); // Trig async flag for EEPROM saving + } + *((uint16_t*)&i2cs_w_buff[1]) = keyboard_get_hold_period(); + + i2cs_w_len = 3; + } else if (reg == REG_ID_FRQ) { + if (is_write) + reg_set_value(REG_ID_FRQ, i2cs_r_buff[1]); + i2cs_w_buff[1] = reg_get_value(REG_ID_FRQ); + } else if (reg == REG_ID_FIF) { + struct fifo_item item = {0}; + fifo_dequeue(&item); + i2cs_w_buff[0] = item.state; + i2cs_w_buff[1] = item.key; + } else if (reg == REG_ID_INT) { + if (is_write) + reg_set_value(REG_ID_INT, 0); + i2cs_w_buff[1] = reg_get_value(REG_ID_INT); + LL_GPIO_SetOutputPin(PICO_IRQ_GPIO_Port, PICO_IRQ_Pin); // De-assert the IRQ signal + } else if (reg == REG_ID_VER) { + i2cs_w_buff[1] = reg_get_value(REG_ID_VER); + } else if (reg == REG_ID_TYP) { + i2cs_w_buff[1] = reg_get_value(REG_ID_TYP); + } else if (reg == REG_ID_BAT) { + i2cs_w_buff[1] = reg_get_value(REG_ID_BAT); + } else if (reg == REG_ID_RTC_CFG) { + if (is_write) { + rtc_reg_xor_events |= reg_get_value(REG_ID_RTC_CFG) ^ i2cs_r_buff[1]; // Using a "OR" set style to avoid loosing change before processing it + reg_set_value(REG_ID_RTC_CFG, i2cs_r_buff[1]); + } + i2cs_w_buff[1] = reg_get_value(REG_ID_RTC_CFG); + } else if (reg == REG_ID_RTC_DATE) { + RTC_DateTypeDef date_s = {0}; + if (is_write) { + i2cs_RTC_date_from_buffer(&date_s, &i2cs_r_buff[1]); + + HAL_RTC_SetDate(&hrtc, &date_s, RTC_FORMAT_BIN); + } + + HAL_RTC_GetDate(&hrtc, &date_s, RTC_FORMAT_BIN); + i2cs_fill_buffer_RTC_date(&i2cs_w_buff[1], &date_s); + + i2cs_w_len = 5; + } else if (reg == REG_ID_RTC_TIME) { + RTC_TimeTypeDef time_s = {0}; + if (is_write) { + i2cs_RTC_time_from_buffer(&time_s, &i2cs_r_buff[1]); + + HAL_RTC_SetTime(&hrtc, &time_s, RTC_FORMAT_BIN); + } + + HAL_RTC_GetTime(&hrtc, &time_s, RTC_FORMAT_BIN); + i2cs_fill_buffer_RTC_time(&i2cs_w_buff[1], &time_s); + + i2cs_w_len = 4; + } else if (reg == REG_ID_RTC_ALARM_DATE) { + if (is_write) + i2cs_RTC_date_from_buffer(&rtc_alarm_date._s, &i2cs_r_buff[1]); + + i2cs_fill_buffer_RTC_date(&i2cs_w_buff[1], &rtc_alarm_date._s); + + i2cs_w_len = 5; + } else if (reg == REG_ID_RTC_ALARM_TIME) { + if (is_write) + i2cs_RTC_time_from_buffer(&rtc_alarm_time._s, &i2cs_r_buff[1]); + + i2cs_fill_buffer_RTC_time(&i2cs_w_buff[1], &rtc_alarm_time._s); + + i2cs_w_len = 4; + } else if (reg == REG_ID_KEY) { + i2cs_w_buff[0] = fifo_count(); + i2cs_w_buff[0] |= keyboard_get_numlock() ? KEY_NUMLOCK : 0x00; + i2cs_w_buff[0] |= keyboard_get_capslock() ? KEY_CAPSLOCK : 0x00; + } else if (reg == REG_ID_C64_MTX) { + //memcpy(write_buffer + 1, io_matrix, sizeof(io_matrix)); + *((uint32_t*)(&i2cs_w_buff[1]) + 0) = *((uint32_t*)(io_matrix) + 0); + *((uint32_t*)(&i2cs_w_buff[1]) + 1) = *((uint32_t*)(io_matrix) + 1); + i2cs_w_buff[9] = io_matrix[8]; + + i2cs_w_len = 10; + } else if (reg == REG_ID_C64_JS) { + i2cs_w_buff[1] = js_bits; + } else if (reg == REG_ID_PWR_CTRL) { + if (is_write) + reg_set_value(REG_ID_PWR_CTRL, i2cs_r_buff[1]); + i2cs_w_buff[1] = reg_get_value(REG_ID_PWR_CTRL); + } else { + i2cs_w_buff[0] = 0; + i2cs_w_buff[1] = 0; + } + + i2cs_state = I2CS_STATE_REG_ANSWER; + i2cs_w_idx = 0; + + HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, i2cs_w_buff, i2cs_w_len, I2C_FIRST_AND_LAST_FRAME); + + i2cs_rearm_counter = uptime_ms(); + } + } + } +} + +extern void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) { + if (hi2c == &hi2c1) { + i2cs_r_idx++; + + if (i2cs_state == I2CS_STATE_REG_REQUEST) { + const uint8_t is_write = (uint8_t)(i2cs_r_buff[0] & (1 << 7)); + const uint8_t reg = (uint8_t)(i2cs_r_buff[0] & ~(1 << 7)); + uint8_t bytes_needed = 0; + + // Check for another mandatories bytes depending on register requested + if (reg == REG_ID_BKL || + reg == REG_ID_BK2 || + reg == REG_ID_SYS_CFG || + reg == REG_ID_INT_CFG || + reg == REG_ID_FRQ) { + if (is_write) + bytes_needed = 1; + } else if (reg == REG_ID_DEB) { + if (is_write) + bytes_needed = 2; + } else if (reg == REG_ID_RTC_DATE || + reg == REG_ID_RTC_ALARM_DATE || + reg == REG_ID_RTC_TIME || + reg == REG_ID_RTC_ALARM_TIME) { + if (is_write) + bytes_needed = 3; + } + + if (bytes_needed > 0) + HAL_I2C_Slave_Sequential_Receive_IT(hi2c, i2cs_r_buff + i2cs_r_idx, bytes_needed, I2C_NEXT_FRAME); // This write the second or more received byte to i2cs_r_buff[1] + } + } +} + +extern void HAL_I2C_ListenCpltCallback (I2C_HandleTypeDef *hi2c) { + if (hi2c == &hi2c1) { + if (i2cs_state == I2CS_STATE_REG_ANSWER) + i2cs_state = I2CS_STATE_IDLE; + + HAL_I2C_EnableListen_IT(hi2c); + } +} + +extern void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) { + if (hi2c == &hi2c1) + if (HAL_I2C_GetError(hi2c) != HAL_I2C_ERROR_AF) { + //Error_Handler(); + // Actually this will trigger the watchdog and restart the system... That can ruin the day of the user. + NVIC_SystemReset(); + } +} diff --git a/Core/Src/keyboard.c b/Core/Src/keyboard.c index 0e26d47..0876033 100644 --- a/Core/Src/keyboard.c +++ b/Core/Src/keyboard.c @@ -152,27 +152,27 @@ static void transition_to(struct list_item * const p_item, const enum key_state switch (p_entry->mod) { case MOD_ALT: - if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + if (reg_is_bit_set(REG_ID_SYS_CFG, CFG_REPORT_MODS)) chr = KEY_MOD_ALT; break; case MOD_SHL: - if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + if (reg_is_bit_set(REG_ID_SYS_CFG, CFG_REPORT_MODS)) chr = KEY_MOD_SHL; break; case MOD_SHR: - if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + if (reg_is_bit_set(REG_ID_SYS_CFG, CFG_REPORT_MODS)) chr = KEY_MOD_SHR; break; case MOD_SYM: - if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + if (reg_is_bit_set(REG_ID_SYS_CFG, CFG_REPORT_MODS)) chr = KEY_MOD_SYM; break; case MOD_CTRL: - if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS)) + if (reg_is_bit_set(REG_ID_SYS_CFG, CFG_REPORT_MODS)) chr = KEY_MOD_CTRL; break; @@ -182,7 +182,7 @@ static void transition_to(struct list_item * const p_item, const enum key_state capslock_changed = 1; } - if (reg_is_bit_set(REG_ID_CFG, CFG_USE_MODS)) { + if (reg_is_bit_set(REG_ID_SYS_CFG, CFG_USE_MODS)) { const uint8_t shift = (mods[MOD_SHL] || mods[MOD_SHR]); const uint8_t alt = mods[MOD_ALT] | numlock; //const uint8_t ctrl = mods[MOD_CTRL]; diff --git a/Core/Src/main.c b/Core/Src/main.c index 4ea3c70..b568d08 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -27,6 +27,7 @@ #include "eeprom.h" #include "fifo.h" #include "keyboard.h" +#include "i2cs.h" #include "regs.h" #include "rtc.h" @@ -40,9 +41,6 @@ #define DEFAULT_KBD_DEB (KEY_HOLD_TIME) #define DEFAULT_RCT_CFG (0x00) -#define I2CS_REARM_TIMEOUT 500 -#define I2CS_W_BUFF_LEN 31+1 // The last one must be only a 0 value, TODO: another cleaner way? - #ifdef DEBUG #define DEBUG_UART_MSG(msg) HAL_UART_Transmit(&huart1, (uint8_t*)msg, sizeof(msg)-1, 1000) //#define DEBUG_UART_MSG2(d,s) HAL_UART_Transmit(&huart1, (uint8_t*)d, s, 200) @@ -51,12 +49,6 @@ // Private typedef ----------------------------------------------------------- -enum i2cs_state { - //I2CS_STATE_HALT, - I2CS_STATE_IDLE, - I2CS_STATE_REG_REQUEST, - I2CS_STATE_REG_ANSWER -}; // Private variables --------------------------------------------------------- @@ -79,20 +71,10 @@ extern UART_HandleTypeDef huart3; volatile uint32_t systicks_counter = 0; // 1 MHz systick counter static uint32_t pmu_check_counter = 0; -static uint32_t i2cs_rearm_counter = 0; - -static uint8_t i2cs_r_buff[5]; -static volatile uint8_t i2cs_r_idx = 0; -static uint8_t i2cs_w_buff[I2CS_W_BUFF_LEN]; -static volatile uint8_t i2cs_w_idx = 0; -static volatile uint8_t i2cs_w_len = 0; -static enum i2cs_state i2cs_state = I2CS_STATE_IDLE; static uint8_t keycb_start = 0; static uint32_t head_phone_status = 0; // TODO: Combine status registers -static volatile uint8_t rtc_reg_xor_events = 0; - volatile uint8_t stop_mode_active = 0; volatile uint8_t pmu_irq = 0; @@ -117,202 +99,6 @@ extern void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { } } -extern void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) { - if (hi2c == &hi2c1) { - // I2C slave addr match error detection - if (AddrMatchCode != 0x3E) // 0x1F << 1 - return; - - if (TransferDirection == I2C_DIRECTION_TRANSMIT) { - if (i2cs_state == I2CS_STATE_IDLE) { - i2cs_state = I2CS_STATE_REG_REQUEST; - - i2cs_r_idx = 0; - HAL_I2C_Slave_Sequential_Receive_IT(hi2c, i2cs_r_buff, 1, I2C_FIRST_FRAME); // This write the first received byte to i2cs_r_buff[0] - - i2cs_rearm_counter = uptime_ms(); - } - } - - if (TransferDirection == I2C_DIRECTION_RECEIVE) { - if (i2cs_state == I2CS_STATE_REG_REQUEST) { - const uint8_t is_write = (uint8_t)(i2cs_r_buff[0] & (1 << 7)); - const uint8_t reg = (uint8_t)(i2cs_r_buff[0] & ~(1 << 7)); - - i2cs_w_buff[0] = reg; - i2cs_w_len = 2; - - if (reg == REG_ID_BKL) { // We wait an another byte for these registers - if (is_write) - lcd_backlight_update(i2cs_r_buff[1]); - i2cs_w_buff[1] = reg_get_value(REG_ID_BKL); - } else if (reg == REG_ID_BK2) { - if (is_write) - kbd_backlight_update(i2cs_r_buff[1]); - i2cs_w_buff[1] = reg_get_value(REG_ID_BK2); - } else if (reg == REG_ID_CFG) { - if (is_write) - reg_set_value(REG_ID_CFG, i2cs_r_buff[1]); - i2cs_w_buff[1] = reg_get_value(REG_ID_CFG); - } else if (reg == REG_ID_INT_CFG) { - if (is_write) - reg_set_value(REG_ID_INT_CFG, i2cs_r_buff[1]); - i2cs_w_buff[1] = reg_get_value(REG_ID_INT_CFG); - } else if (reg == REG_ID_DEB) { - if (is_write) { - keyboard_set_hold_period(*((uint16_t*)&i2cs_r_buff[1])); - reg_set_value(REG_ID_DEB, 0); // Trig async flag for EEPROM saving - } - *((uint16_t*)&i2cs_w_buff[1]) = keyboard_get_hold_period(); - - i2cs_w_len = 3; - } else if (reg == REG_ID_FRQ) { - if (is_write) - reg_set_value(REG_ID_FRQ, i2cs_r_buff[1]); - i2cs_w_buff[1] = reg_get_value(REG_ID_FRQ); - } else if (reg == REG_ID_FIF) { - struct fifo_item item = {0}; - fifo_dequeue(&item); - i2cs_w_buff[0] = item.state; - i2cs_w_buff[1] = item.key; - } else if (reg == REG_ID_INT) { - if (is_write) - reg_set_value(REG_ID_INT, 0); - i2cs_w_buff[1] = reg_get_value(REG_ID_INT); - LL_GPIO_SetOutputPin(PICO_IRQ_GPIO_Port, PICO_IRQ_Pin); // De-assert the IRQ signal - } else if (reg == REG_ID_VER) { - i2cs_w_buff[1] = reg_get_value(REG_ID_VER); - } else if (reg == REG_ID_TYP) { - i2cs_w_buff[1] = reg_get_value(REG_ID_TYP); - } else if (reg == REG_ID_BAT) { - i2cs_w_buff[1] = reg_get_value(REG_ID_BAT); - } else if (reg == REG_ID_RTC_CFG) { - if (is_write) { - rtc_reg_xor_events |= reg_get_value(REG_ID_RTC_CFG) ^ i2cs_r_buff[1]; // Using a "OR" set style to avoid loosing change before processing it - reg_set_value(REG_ID_RTC_CFG, i2cs_r_buff[1]); - } - i2cs_w_buff[1] = reg_get_value(REG_ID_RTC_CFG); - } else if (reg == REG_ID_RTC_DATE) { - RTC_DateTypeDef date_s = {0}; - if (is_write) { - i2cs_RTC_date_from_buffer(&date_s, &i2cs_r_buff[1]); - - HAL_RTC_SetDate(&hrtc, &date_s, RTC_FORMAT_BIN); - } - - HAL_RTC_GetDate(&hrtc, &date_s, RTC_FORMAT_BIN); - i2cs_fill_buffer_RTC_date(&i2cs_w_buff[1], &date_s); - - i2cs_w_len = 5; - } else if (reg == REG_ID_RTC_TIME) { - RTC_TimeTypeDef time_s = {0}; - if (is_write) { - i2cs_RTC_time_from_buffer(&time_s, &i2cs_r_buff[1]); - - HAL_RTC_SetTime(&hrtc, &time_s, RTC_FORMAT_BIN); - } - - HAL_RTC_GetTime(&hrtc, &time_s, RTC_FORMAT_BIN); - i2cs_fill_buffer_RTC_time(&i2cs_w_buff[1], &time_s); - - i2cs_w_len = 4; - } else if (reg == REG_ID_RTC_ALARM_DATE) { - if (is_write) - i2cs_RTC_date_from_buffer(&rtc_alarm_date._s, &i2cs_r_buff[1]); - - i2cs_fill_buffer_RTC_date(&i2cs_w_buff[1], &rtc_alarm_date._s); - - i2cs_w_len = 5; - } else if (reg == REG_ID_RTC_ALARM_TIME) { - if (is_write) - i2cs_RTC_time_from_buffer(&rtc_alarm_time._s, &i2cs_r_buff[1]); - - i2cs_fill_buffer_RTC_time(&i2cs_w_buff[1], &rtc_alarm_time._s); - - i2cs_w_len = 4; - } else if (reg == REG_ID_KEY) { - i2cs_w_buff[0] = fifo_count(); - i2cs_w_buff[0] |= keyboard_get_numlock() ? KEY_NUMLOCK : 0x00; - i2cs_w_buff[0] |= keyboard_get_capslock() ? KEY_CAPSLOCK : 0x00; - } else if (reg == REG_ID_C64_MTX) { - //memcpy(write_buffer + 1, io_matrix, sizeof(io_matrix)); - *((uint32_t*)(&i2cs_w_buff[1]) + 0) = *((uint32_t*)(io_matrix) + 0); - *((uint32_t*)(&i2cs_w_buff[1]) + 1) = *((uint32_t*)(io_matrix) + 1); - i2cs_w_buff[9] = io_matrix[8]; - - i2cs_w_len = 10; - } else if (reg == REG_ID_C64_JS) { - i2cs_w_buff[1] = js_bits; - } else if (reg == REG_ID_PWR_CTRL) { - if (is_write) - reg_set_value(REG_ID_PWR_CTRL, i2cs_r_buff[1]); - i2cs_w_buff[1] = reg_get_value(REG_ID_PWR_CTRL); - } else { - i2cs_w_buff[0] = 0; - i2cs_w_buff[1] = 0; - } - - i2cs_state = I2CS_STATE_REG_ANSWER; - i2cs_w_idx = 0; - - HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, i2cs_w_buff, i2cs_w_len, I2C_FIRST_AND_LAST_FRAME); - - i2cs_rearm_counter = uptime_ms(); - } - } - } -} - -extern void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) { - if (hi2c == &hi2c1) { - i2cs_r_idx++; - - if (i2cs_state == I2CS_STATE_REG_REQUEST) { - const uint8_t is_write = (uint8_t)(i2cs_r_buff[0] & (1 << 7)); - const uint8_t reg = (uint8_t)(i2cs_r_buff[0] & ~(1 << 7)); - uint8_t bytes_needed = 0; - - // Check for another mandatories bytes depending on register requested - if (reg == REG_ID_BKL || - reg == REG_ID_BK2 || - reg == REG_ID_CFG || - reg == REG_ID_INT_CFG || - reg == REG_ID_FRQ) { - if (is_write) - bytes_needed = 1; - } else if (reg == REG_ID_DEB) { - if (is_write) - bytes_needed = 2; - } else if (reg == REG_ID_RTC_DATE || - reg == REG_ID_RTC_ALARM_DATE || - reg == REG_ID_RTC_TIME || - reg == REG_ID_RTC_ALARM_TIME) { - if (is_write) - bytes_needed = 3; - } - - if (bytes_needed > 0) - HAL_I2C_Slave_Sequential_Receive_IT(hi2c, i2cs_r_buff + i2cs_r_idx, bytes_needed, I2C_NEXT_FRAME); // This write the second or more received byte to i2cs_r_buff[1] - } - } -} - -extern void HAL_I2C_ListenCpltCallback (I2C_HandleTypeDef *hi2c) { - if (hi2c == &hi2c1) { - if (i2cs_state == I2CS_STATE_REG_ANSWER) - i2cs_state = I2CS_STATE_IDLE; - - HAL_I2C_EnableListen_IT(hi2c); - } -} - -extern void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) { - if (hi2c == &hi2c1) - if (HAL_I2C_GetError(hi2c) != HAL_I2C_ERROR_AF) - Error_Handler(); - // Actually this will trigger the watchdog and restart the system... That can ruin the day of the user. -} - #ifdef DEBUG void uart_rawdata_write(uint32_t c, size_t s, uint8_t swap) { uint8_t r[4]; @@ -626,7 +412,7 @@ static void key_cb(char key, enum key_state state) { int_trig = 1; } - if (reg_is_bit_set(REG_ID_CFG, CFG_OVERFLOW_ON)) fifo_enqueue_force(item); + if (reg_is_bit_set(REG_ID_SYS_CFG, CFG_OVERFLOW_ON)) fifo_enqueue_force(item); } #ifndef UART_PICO_INTERFACE diff --git a/Core/Src/regs.c b/Core/Src/regs.c index 0828b04..bf83cde 100644 --- a/Core/Src/regs.c +++ b/Core/Src/regs.c @@ -9,9 +9,13 @@ extern RTC_HandleTypeDef hrtc; static uint8_t regs[REG_ID_LAST] = {0}; -static uint8_t regs_unsync[REG_ID_LAST] = {0}; static uint32_t eeprom_refresh_counter; +static uint32_t regs_unsync[(REG_ID_LAST / 32) + 1] = {0}; +#define REGS_UNSYNC_SET(x) regs_unsync[(x / 32)] |= (uint32_t)(1U << (x % 32)) +#define REGS_UNSYNC_UNSET(x) regs_unsync[(x / 32)] &= ~((uint32_t)(1U << (x % 32))) +#define REGS_UNSYNC_GET(x) ((regs_unsync[(x / 32)] >> (x % 32)) & (uint32_t)0x1) + inline uint8_t reg_get_value(enum reg_id reg) { if (reg >= REG_ID_LAST) return 0; @@ -28,7 +32,7 @@ inline void reg_set_value(enum reg_id reg, uint8_t value) { return; regs[reg] = value; - regs_unsync[reg] = 1; + REGS_UNSYNC_SET(reg); eeprom_refresh_counter = uptime_ms(); } @@ -44,29 +48,30 @@ inline void reg_set_bit(enum reg_id reg, uint8_t bit) { return; regs[reg] |= bit; - regs_unsync[reg] = 1; + REGS_UNSYNC_SET(reg); eeprom_refresh_counter = uptime_ms(); } /* * | Bit | Name | Description | -| ------ |:----------------:| ------------------------------------------------------------------:| -| 7 | CFG_USE_MODS | Should Alt, Sym and the Shift keys modify the keys being reported. | -| 6 | CFG_REPORT_MODS | Should Alt, Sym and the Shift keys be reported as well. | -| 5 | CFG_PANIC_INT | Currently not implemented. | -| 4 | CFG_KEY_INT | Should an interrupt be generated when a key is pressed. | -| 3 | CFG_NUMLOCK_INT | Should an interrupt be generated when Num Lock is toggled. | -| 2 | CFG_CAPSLOCK_INT | Should an interrupt be generated when Caps Lock is toggled. | -| 1 | CFG_OVERFLOW_INT | Should an interrupt be generated when a FIFO overflow happens. | -| 0 | CFG_OVERFLOW_ON | When a FIFO overflow happens, should the new entry still be pushed, overwriting the oldest one. If 0 then new entry is lost. | + * | ------ |:----------------:| ------------------------------------------------------------------:| + * | 7 | CFG_USE_MODS | Should Alt, Sym and the Shift keys modify the keys being reported. | + * | 6 | CFG_REPORT_MODS | Should Alt, Sym and the Shift keys be reported as well. | + * | 5 | CFG_PANIC_INT | Currently not implemented. | + * | 4 | CFG_KEY_INT | Should an interrupt be generated when a key is pressed. | + * | 3 | CFG_NUMLOCK_INT | Should an interrupt be generated when Num Lock is toggled. | + * | 2 | CFG_CAPSLOCK_INT | Should an interrupt be generated when Caps Lock is toggled. | + * | 1 | CFG_OVERFLOW_INT | Should an interrupt be generated when a FIFO overflow happens. | + * | 0 | CFG_OVERFLOW_ON | When a FIFO overflow happens, should the new entry still be pushed,| + * | | | overwriting the oldest one. If 0 then new entry is lost. | */ void reg_init(void) { uint32_t buff; regs[REG_ID_VER] = (uint8_t)((VERSION_MAJOR << 4) | VERSION_MINOR); // 1.2 => (0x1 << 4) | 0x2 - EEPROM_ReadVariable(EEPROM_VAR_CFG, (EEPROM_Value*)&buff); - regs[REG_ID_CFG] = (uint8_t)((buff >> 8) & 0xFF); + EEPROM_ReadVariable(REG_ID_SYS_CFG, (EEPROM_Value*)&buff); + regs[REG_ID_SYS_CFG] = (uint8_t)((buff >> 8) & 0xFF); regs[REG_ID_INT_CFG] = (uint8_t)(buff & 0xFF); EEPROM_ReadVariable(EEPROM_VAR_KBD, (EEPROM_Value*)&buff); @@ -100,33 +105,33 @@ uint32_t reg_check_and_save_eeprom(void) { uint8_t need_save = 0; for (size_t i = 0; i < REG_ID_LAST; i++) - if (regs_unsync[i] == 1) { + if (REGS_UNSYNC_GET(i) == 1) { need_save = 1; break; } if (need_save == 1) { - if (regs_unsync[REG_ID_CFG] == 1) - result |= EEPROM_WriteVariable(EEPROM_VAR_CFG, (EEPROM_Value)(uint16_t)((regs[REG_ID_CFG] << 8) | regs[REG_ID_INT_CFG]), EEPROM_SIZE16); + if (REGS_UNSYNC_GET(REG_ID_SYS_CFG) == 1) + result |= EEPROM_WriteVariable(EEPROM_VAR_CFG, (EEPROM_Value)(uint16_t)((regs[REG_ID_SYS_CFG] << 8) | regs[REG_ID_INT_CFG]), EEPROM_SIZE16); - if (regs_unsync[REG_ID_DEB] == 1 || regs_unsync[REG_ID_FRQ] == 1) + if (REGS_UNSYNC_GET(REG_ID_DEB) == 1 || REGS_UNSYNC_GET(REG_ID_FRQ) == 1) result |= EEPROM_WriteVariable(EEPROM_VAR_KBD, (EEPROM_Value)(uint32_t)((keyboard_get_hold_period() << 16) | regs[REG_ID_FRQ]), EEPROM_SIZE32); - if (regs_unsync[REG_ID_BKL] == 1 || regs_unsync[REG_ID_BK2] == 1) + if (REGS_UNSYNC_GET(REG_ID_BKL) == 1 || REGS_UNSYNC_GET(REG_ID_BK2) == 1) result |= EEPROM_WriteVariable(EEPROM_VAR_BCKL, (EEPROM_Value)(uint16_t)((regs[REG_ID_BKL] << 8) | regs[REG_ID_BK2]), EEPROM_SIZE16); - if (regs_unsync[REG_ID_RTC_ALARM_TIME] == 1 || regs_unsync[REG_ID_RTC_CFG] == 1) { + if (REGS_UNSYNC_GET(REG_ID_RTC_ALARM_TIME) == 1 || REGS_UNSYNC_GET(REG_ID_RTC_CFG) == 1) { HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, ((rtc_alarm_time.raw & 0xFF) << 8) | regs[REG_ID_RTC_CFG]); HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, rtc_alarm_time.raw >> 16); } - if (regs_unsync[REG_ID_RTC_ALARM_DATE] == 1) { + if (REGS_UNSYNC_GET(REG_ID_RTC_ALARM_DATE) == 1) { HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR4, rtc_alarm_date.raw & 0xFFFF); HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, rtc_alarm_date.raw >> 16); } for (size_t i = 0; i < REG_ID_LAST; i++) - regs_unsync[i] = 0; + REGS_UNSYNC_UNSET(i); } return result; diff --git a/README.md b/README.md index 8a744ec..50087b0 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,12 @@ The main differences with the original firmware are the followings: - drastic reduction in the STM32's electricity consumption when running (~3.5 mA), - clean up (by removing stm32duino dependencies, use STM32HAL instead, maybe I'll switch to libopencm3 someday...) to reduce binary size (~25 KB) and allow more features to be implemented, - added configuration saving solution (using internal flash, including backlight option), -- new I2C registers and structure (keeping compatible access to REG_ID_TYP and REG_ID_VER registers to check how to handle comm from pico board side), +- new I2C registers memory allocation and structure (keeping compatible access to REG_ID_TYP and REG_ID_VER registers to check how to handle comm from pico board side)(WIP), - interrupt event output to pico board can be configured during runtime (for keyboard event or RTC alarm), -- rewriten or added some debug UART interface message, -- internal RTC access through dedicated I2C registers (WIP), -- lighten AXP2101 PMIC driver. +- rewriten or added some debug UART interface message (only when compiled in DEBUG release type), +- internal RTC access through dedicated I2C registers, +- auto wake-up using RTC (WIP), +- lighten AXP2101 PMIC driver (based on X-PowersLib). ## Compile This source code can be compiled using ARM gcc toolchain (using v13) in path and using make program. @@ -23,9 +24,18 @@ But this makes them incompatible with official firmware. (More details to come a If you plan using pico official firmware (PicoMite, etc.), you should set I2C_REGS_COMPAT = 1 in the Makefile. +## TODO +- Registers memory structure/allocation rewrite +- Auto wake-up +- IRQ to Pico management (register exist but does nothing) +- Add a Pico test program for registers/features implemented +- add few wiki page to detail the I2C protocol, added features, etc. + ## Important notes The current implementation of this firmware is subject to change until the v1 release. +Some features can be unstable or buggy and are marked as pre-release. A test program will be developped soon to provide some regression testing. + The permanent settings (EEPROM) save can be broken between 0.x version, it is recommanded to make a full flash erase before updating, as EEPROM configuration survives update.