Registers tweaks

Prepare for new registers structure used in v1
This commit is contained in:
JackCarterSmith 2025-06-07 15:57:31 +02:00
parent e1a77fc1ca
commit cdee81d3ff
Signed by: JackCarterSmith
GPG Key ID: 832E52F4E23F8F24
10 changed files with 334 additions and 267 deletions

View File

@ -145,6 +145,7 @@ extern volatile uint32_t systicks_counter;
extern volatile uint8_t pmu_irq; extern volatile uint8_t pmu_irq;
extern volatile uint8_t stop_mode_active; 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_TimeTypeDef_u rtc_alarm_time;
extern volatile RTC_DateTypeDef_u rtc_alarm_date; extern volatile RTC_DateTypeDef_u rtc_alarm_date;

20
Core/Inc/i2cs.h Normal file
View File

@ -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_ */

View File

@ -8,7 +8,7 @@ enum reg_id {
REG_ID_TYP = 0x00, //!< firmware type (0=official, others=custom) REG_ID_TYP = 0x00, //!< firmware type (0=official, others=custom)
REG_ID_VER = 0x01, //!< fw version (7:4=Major, 3:0=Minor) REG_ID_VER = 0x01, //!< fw version (7:4=Major, 3:0=Minor)
#ifdef I2C_REGS_COMPAT #ifdef I2C_REGS_COMPAT
REG_ID_CFG = 0x02, // config REG_ID_SYS_CFG = 0x02, // config
REG_ID_INT = 0x03, // interrupt status REG_ID_INT = 0x03, // interrupt status
REG_ID_KEY = 0x04, // key status REG_ID_KEY = 0x04, // key status
REG_ID_BKL = 0x05, // backlight steps (0-9) 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_DATE = 0x12, // RTC alarm date
REG_ID_RTC_ALARM_TIME = 0x13, // RTC alarm time REG_ID_RTC_ALARM_TIME = 0x13, // RTC alarm time
#else #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_CFG = 0x03, //!< IRQ config
REG_ID_INT = 0x04, //!< interrupt status REG_ID_PWR_CTRL = 0x04, //!< Power control (0: idle, 1: pico reset, 2: system reset, 3: reserved, 4: sleep, 5: full-shutdown)
REG_ID_BKL = 0x05, //!< backlight steps (0-9) REG_ID_RTC_CFG = 0x05, //!< RTC general config
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_RTC_CFG = 0x0A, //!< RTC general config // TODO: REG_ID_CFG_1 - 32b (RW)
REG_ID_RTC_DATE = 0x0B, //!< RTC date REG_ID_DEB = 0x06, //!< debounce cfg (time in ms)
REG_ID_RTC_TIME = 0x0C, //!< RTC time REG_ID_FRQ = 0x07, //!< poll freq cfg (time in ms)
REG_ID_RTC_ALARM_DATE = 0x0D, //!< RTC alarm date REG_ID_BKL = 0x08, //!< backlight steps (0-9)
REG_ID_RTC_ALARM_TIME = 0x0E, //!< RTC alarm time REG_ID_BK2 = 0x09, //!< keyboard backlight (0-9)
REG_ID_KEY = 0x10, //!< key status // TODO: REG_ID_RTC_DATE - 32b (RW)
REG_ID_FIF = 0x11, //!< fifo REG_ID_RTC_DATE = 0x0A, //!< RTC date
REG_ID_C64_MTX = 0x12, //!< read c64 matrix // TODO: REG_ID_RTC_TIME - 32b (RW)
REG_ID_C64_JS = 0x13, //!< joystick io bits 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 #endif
REG_ID_LAST 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_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_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 #define CFG_USE_MODS (1 << 7) // Should Alt, Sym and Shifts modify the keys reported

View File

@ -2,6 +2,6 @@
#define VERSION_H_ #define VERSION_H_
#define VERSION_MAJOR (0) #define VERSION_MAJOR (0)
#define VERSION_MINOR (5) #define VERSION_MINOR (6)
#endif /* VERSION_H_ */ #endif /* VERSION_H_ */

View File

@ -37,6 +37,7 @@ UART_HandleTypeDef huart1;
UART_HandleTypeDef huart3; UART_HandleTypeDef huart3;
#endif #endif
volatile uint8_t rtc_reg_xor_events = 0;
volatile RTC_TimeTypeDef_u rtc_alarm_time = {.raw = 0x00000000}; volatile RTC_TimeTypeDef_u rtc_alarm_time = {.raw = 0x00000000};
volatile RTC_DateTypeDef_u rtc_alarm_date = {.raw = 0x00010101}; volatile RTC_DateTypeDef_u rtc_alarm_date = {.raw = 0x00010101};

221
Core/Src/i2cs.c Normal file
View File

@ -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();
}
}

View File

@ -152,27 +152,27 @@ static void transition_to(struct list_item * const p_item, const enum key_state
switch (p_entry->mod) { switch (p_entry->mod) {
case MOD_ALT: 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; chr = KEY_MOD_ALT;
break; break;
case MOD_SHL: 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; chr = KEY_MOD_SHL;
break; break;
case MOD_SHR: 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; chr = KEY_MOD_SHR;
break; break;
case MOD_SYM: 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; chr = KEY_MOD_SYM;
break; break;
case MOD_CTRL: 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; chr = KEY_MOD_CTRL;
break; break;
@ -182,7 +182,7 @@ static void transition_to(struct list_item * const p_item, const enum key_state
capslock_changed = 1; 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 shift = (mods[MOD_SHL] || mods[MOD_SHR]);
const uint8_t alt = mods[MOD_ALT] | numlock; const uint8_t alt = mods[MOD_ALT] | numlock;
//const uint8_t ctrl = mods[MOD_CTRL]; //const uint8_t ctrl = mods[MOD_CTRL];

View File

@ -27,6 +27,7 @@
#include "eeprom.h" #include "eeprom.h"
#include "fifo.h" #include "fifo.h"
#include "keyboard.h" #include "keyboard.h"
#include "i2cs.h"
#include "regs.h" #include "regs.h"
#include "rtc.h" #include "rtc.h"
@ -40,9 +41,6 @@
#define DEFAULT_KBD_DEB (KEY_HOLD_TIME) #define DEFAULT_KBD_DEB (KEY_HOLD_TIME)
#define DEFAULT_RCT_CFG (0x00) #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 #ifdef DEBUG
#define DEBUG_UART_MSG(msg) HAL_UART_Transmit(&huart1, (uint8_t*)msg, sizeof(msg)-1, 1000) #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) //#define DEBUG_UART_MSG2(d,s) HAL_UART_Transmit(&huart1, (uint8_t*)d, s, 200)
@ -51,12 +49,6 @@
// Private typedef ----------------------------------------------------------- // Private typedef -----------------------------------------------------------
enum i2cs_state {
//I2CS_STATE_HALT,
I2CS_STATE_IDLE,
I2CS_STATE_REG_REQUEST,
I2CS_STATE_REG_ANSWER
};
// Private variables --------------------------------------------------------- // Private variables ---------------------------------------------------------
@ -79,20 +71,10 @@ extern UART_HandleTypeDef huart3;
volatile uint32_t systicks_counter = 0; // 1 MHz systick counter volatile uint32_t systicks_counter = 0; // 1 MHz systick counter
static uint32_t pmu_check_counter = 0; 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 uint8_t keycb_start = 0;
static uint32_t head_phone_status = 0; // TODO: Combine status registers 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 stop_mode_active = 0;
volatile uint8_t pmu_irq = 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 #ifdef DEBUG
void uart_rawdata_write(uint32_t c, size_t s, uint8_t swap) { void uart_rawdata_write(uint32_t c, size_t s, uint8_t swap) {
uint8_t r[4]; uint8_t r[4];
@ -626,7 +412,7 @@ static void key_cb(char key, enum key_state state) {
int_trig = 1; 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 #ifndef UART_PICO_INTERFACE

View File

@ -9,9 +9,13 @@
extern RTC_HandleTypeDef hrtc; extern RTC_HandleTypeDef hrtc;
static uint8_t regs[REG_ID_LAST] = {0}; 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 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) { inline uint8_t reg_get_value(enum reg_id reg) {
if (reg >= REG_ID_LAST) if (reg >= REG_ID_LAST)
return 0; return 0;
@ -28,7 +32,7 @@ inline void reg_set_value(enum reg_id reg, uint8_t value) {
return; return;
regs[reg] = value; regs[reg] = value;
regs_unsync[reg] = 1; REGS_UNSYNC_SET(reg);
eeprom_refresh_counter = uptime_ms(); eeprom_refresh_counter = uptime_ms();
} }
@ -44,29 +48,30 @@ inline void reg_set_bit(enum reg_id reg, uint8_t bit) {
return; return;
regs[reg] |= bit; regs[reg] |= bit;
regs_unsync[reg] = 1; REGS_UNSYNC_SET(reg);
eeprom_refresh_counter = uptime_ms(); eeprom_refresh_counter = uptime_ms();
} }
/* /*
* | Bit | Name | Description | * | Bit | Name | Description |
| ------ |:----------------:| ------------------------------------------------------------------:| * | ------ |:----------------:| ------------------------------------------------------------------:|
| 7 | CFG_USE_MODS | Should Alt, Sym and the Shift keys modify the keys being reported. | * | 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. | * | 6 | CFG_REPORT_MODS | Should Alt, Sym and the Shift keys be reported as well. |
| 5 | CFG_PANIC_INT | Currently not implemented. | * | 5 | CFG_PANIC_INT | Currently not implemented. |
| 4 | CFG_KEY_INT | Should an interrupt be generated when a key is pressed. | * | 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. | * | 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. | * | 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. | * | 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. | * | 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) { void reg_init(void) {
uint32_t buff; uint32_t buff;
regs[REG_ID_VER] = (uint8_t)((VERSION_MAJOR << 4) | VERSION_MINOR); // 1.2 => (0x1 << 4) | 0x2 regs[REG_ID_VER] = (uint8_t)((VERSION_MAJOR << 4) | VERSION_MINOR); // 1.2 => (0x1 << 4) | 0x2
EEPROM_ReadVariable(EEPROM_VAR_CFG, (EEPROM_Value*)&buff); EEPROM_ReadVariable(REG_ID_SYS_CFG, (EEPROM_Value*)&buff);
regs[REG_ID_CFG] = (uint8_t)((buff >> 8) & 0xFF); regs[REG_ID_SYS_CFG] = (uint8_t)((buff >> 8) & 0xFF);
regs[REG_ID_INT_CFG] = (uint8_t)(buff & 0xFF); regs[REG_ID_INT_CFG] = (uint8_t)(buff & 0xFF);
EEPROM_ReadVariable(EEPROM_VAR_KBD, (EEPROM_Value*)&buff); 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; uint8_t need_save = 0;
for (size_t i = 0; i < REG_ID_LAST; i++) for (size_t i = 0; i < REG_ID_LAST; i++)
if (regs_unsync[i] == 1) { if (REGS_UNSYNC_GET(i) == 1) {
need_save = 1; need_save = 1;
break; break;
} }
if (need_save == 1) { if (need_save == 1) {
if (regs_unsync[REG_ID_CFG] == 1) if (REGS_UNSYNC_GET(REG_ID_SYS_CFG) == 1)
result |= EEPROM_WriteVariable(EEPROM_VAR_CFG, (EEPROM_Value)(uint16_t)((regs[REG_ID_CFG] << 8) | regs[REG_ID_INT_CFG]), EEPROM_SIZE16); 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); 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); 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_DR2, ((rtc_alarm_time.raw & 0xFF) << 8) | regs[REG_ID_RTC_CFG]);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, rtc_alarm_time.raw >> 16); 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_DR4, rtc_alarm_date.raw & 0xFFFF);
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, rtc_alarm_date.raw >> 16); HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR5, rtc_alarm_date.raw >> 16);
} }
for (size_t i = 0; i < REG_ID_LAST; i++) for (size_t i = 0; i < REG_ID_LAST; i++)
regs_unsync[i] = 0; REGS_UNSYNC_UNSET(i);
} }
return result; return result;

View File

@ -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), - 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, - 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), - 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), - 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, - rewriten or added some debug UART interface message (only when compiled in DEBUG release type),
- internal RTC access through dedicated I2C registers (WIP), - internal RTC access through dedicated I2C registers,
- lighten AXP2101 PMIC driver. - auto wake-up using RTC (WIP),
- lighten AXP2101 PMIC driver (based on X-PowersLib).
## Compile ## Compile
This source code can be compiled using ARM gcc toolchain (using v13) in path and using make program. 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. 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 ## Important notes
The current implementation of this firmware is subject to change until the v1 release. 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 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. EEPROM configuration survives update.