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 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;

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_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

View File

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

View File

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

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) {
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];

View File

@ -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

View File

@ -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;

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),
- 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.