Last final registers implementation

- Add FEE to linker script
- Debug PrintPMU
- systick overflow check
This commit is contained in:
JackCarterSmith 2025-05-09 19:02:06 +02:00
parent 4f003168c4
commit b6aae3384e
Signed by: JackCarterSmith
GPG Key ID: 832E52F4E23F8F24
6 changed files with 239 additions and 49 deletions

View File

@ -14,11 +14,11 @@
#define XPOWERS_AXP2101_IC_TYPE (0x03)
//#define XPOWERS_AXP2101_DATA_BUFFER1 (0x04)
//#define XPOWERS_AXP2101_DATA_BUFFER2 (0x05)
//#define XPOWERS_AXP2101_DATA_BUFFER3 (0x06)
//#define XPOWERS_AXP2101_DATA_BUFFER4 (0x07)
//#define XPOWERS_AXP2101_DATA_BUFFER_SIZE (4u)
#define XPOWERS_AXP2101_DATA_BUFFER1 (0x04)
#define XPOWERS_AXP2101_DATA_BUFFER2 (0x05)
#define XPOWERS_AXP2101_DATA_BUFFER3 (0x06)
#define XPOWERS_AXP2101_DATA_BUFFER4 (0x07)
#define XPOWERS_AXP2101_DATA_BUFFER_SIZE (4u)
#define XPOWERS_AXP2101_COMMON_CONFIG (0x10)
//#define XPOWERS_AXP2101_BATFET_CTRL (0x12)
@ -49,16 +49,16 @@
//#define XPOWERS_AXP2101_FAST_PWRON_CTRL (0x2B)
#define XPOWERS_AXP2101_ADC_CHANNEL_CTRL (0x30)
//#define XPOWERS_AXP2101_ADC_DATA_RELUST0 (0x34)
//#define XPOWERS_AXP2101_ADC_DATA_RELUST1 (0x35)
//#define XPOWERS_AXP2101_ADC_DATA_RELUST2 (0x36)
//#define XPOWERS_AXP2101_ADC_DATA_RELUST3 (0x37)
//#define XPOWERS_AXP2101_ADC_DATA_RELUST4 (0x38)
//#define XPOWERS_AXP2101_ADC_DATA_RELUST5 (0x39)
//#define XPOWERS_AXP2101_ADC_DATA_RELUST6 (0x3A)
//#define XPOWERS_AXP2101_ADC_DATA_RELUST7 (0x3B)
//#define XPOWERS_AXP2101_ADC_DATA_RELUST8 (0x3C)
//#define XPOWERS_AXP2101_ADC_DATA_RELUST9 (0x3D)
#define XPOWERS_AXP2101_ADC_DATA_RELUST0 (0x34)
#define XPOWERS_AXP2101_ADC_DATA_RELUST1 (0x35)
#define XPOWERS_AXP2101_ADC_DATA_RELUST2 (0x36)
#define XPOWERS_AXP2101_ADC_DATA_RELUST3 (0x37)
#define XPOWERS_AXP2101_ADC_DATA_RELUST4 (0x38)
#define XPOWERS_AXP2101_ADC_DATA_RELUST5 (0x39)
#define XPOWERS_AXP2101_ADC_DATA_RELUST6 (0x3A)
#define XPOWERS_AXP2101_ADC_DATA_RELUST7 (0x3B)
#define XPOWERS_AXP2101_ADC_DATA_RELUST8 (0x3C)
#define XPOWERS_AXP2101_ADC_DATA_RELUST9 (0x3D)
/*
* ------------------ Interrupt registers ---------------------
@ -266,6 +266,15 @@ typedef enum __xpowers_chg_led_mode {
XPOWERS_CHG_LED_CTRL_CHG, // The charging indicator is controlled by the charger
} xpowers_chg_led_mode_t;
typedef enum {
XPOWERS_AXP2101_CHG_TRI_STATE, //tri_charge
XPOWERS_AXP2101_CHG_PRE_STATE, //pre_charge
XPOWERS_AXP2101_CHG_CC_STATE, //constant charge
XPOWERS_AXP2101_CHG_CV_STATE, //constant voltage
XPOWERS_AXP2101_CHG_DONE_STATE, //charge done
XPOWERS_AXP2101_CHG_STOP_STATE, //not charge
} xpowers_chg_status_t;
/*
* ------------- axp2101 interrupt control mask -------------
*/
@ -325,9 +334,18 @@ uint32_t AXP2101_setLowBatShutdownThreshold(uint8_t opt);
uint32_t AXP2101_setSysPowerDownVoltage(uint16_t value);
uint32_t AXP2101_setChargingLedMode(uint8_t mode);
int8_t AXP2101_readDataBuffer(uint8_t *data, uint8_t size);
uint8_t AXP2101_isBatteryConnect(void);
uint8_t AXP2101_isCharging(void);
uint8_t AXP2101_isDischarge(void);
uint8_t AXP2101_isStandby(void);
uint8_t AXP2101_isVbusGood(void);
uint8_t AXP2101_isVbusIn(void);
uint32_t AXP2101_getIrqStatus(uint32_t* out_value);
uint32_t AXP2101_getBatteryPercent(uint8_t* out_value);
xpowers_chg_status_t AXP2101_getChargerStatus(void);
uint16_t AXP2101_getBattVoltage(void);
uint16_t AXP2101_getVbusVoltage(void);
uint16_t AXP2101_getSystemVoltage(void);
#endif /* AXP2101_H_ */

View File

@ -12,6 +12,36 @@ static uint8_t statusRegister[XPOWERS_AXP2101_INTSTS_CNT] = {0};
static uint8_t intRegister[XPOWERS_AXP2101_INTSTS_CNT] = {0};
__STATIC_INLINE int8_t readRegister(uint8_t reg, uint8_t *buf, uint8_t length) {
HAL_StatusTypeDef status;
status = HAL_I2C_Mem_Read(&hi2c2, AXP2101_DEV_I2C_ID, reg, length, buf, 1, 60);
if (status != HAL_OK)
return -1;
return 0;
}
__STATIC_INLINE uint16_t readRegisterH6L8(uint8_t highReg, uint8_t lowReg) {
uint8_t h6;
uint8_t l8;
int8_t h6_s = readRegister(highReg, &h6, 1);
int8_t l8_s = readRegister(lowReg, &l8, 1);
if (h6_s == -1 || l8_s == -1)
return 0;
return ((h6 & 0x3F) << 8) | l8;
}
__STATIC_INLINE uint16_t readRegisterH5L8(uint8_t highReg, uint8_t lowReg) {
uint8_t h5;
uint8_t l8;
int8_t h5_s = readRegister(highReg, &h5, 1);
int8_t l8_s = readRegister(lowReg, &l8, 1);
if (h5_s == -1 || l8_s == -1)
return 0;
return ((h5 & 0x1F) << 8) | l8;
}
__STATIC_INLINE uint8_t clrRegisterBit(uint8_t registers, uint8_t bit) {
uint8_t reg_value = 0;
HAL_StatusTypeDef status;
@ -281,6 +311,12 @@ uint32_t AXP2101_setLowBatShutdownThreshold(uint8_t opt) {
}
int8_t AXP2101_readDataBuffer(uint8_t *data, uint8_t size) {
if (size > XPOWERS_AXP2101_DATA_BUFFER_SIZE)
return -1;
return readRegister(XPOWERS_AXP2101_DATA_BUFFER1, data, size);
}
uint8_t AXP2101_isBatteryConnect(void) {
return getRegisterBit(XPOWERS_AXP2101_STATUS1, 3);
}
@ -293,6 +329,26 @@ uint8_t AXP2101_isCharging(void) {
return (reg_value >> 5) == 0x01;
}
uint8_t AXP2101_isDischarge(void) {
uint8_t res = 0;
readRegister(XPOWERS_AXP2101_STATUS2, &res, 1);
return (res >> 5) == 0x02;
}
uint8_t AXP2101_isStandby(void) {
uint8_t res = 0;
readRegister(XPOWERS_AXP2101_STATUS2, &res, 1);
return (res >> 5) == 0x00;
}
uint8_t AXP2101_isVbusGood(void) {
return getRegisterBit(XPOWERS_AXP2101_STATUS1, 5);
}
uint8_t AXP2101_isVbusIn(void) {
return getRegisterBit(XPOWERS_AXP2101_STATUS2, 3) == 0 && AXP2101_isVbusGood();
}
uint32_t AXP2101_getIrqStatus(uint32_t* out_value) {
HAL_StatusTypeDef status = HAL_OK;
@ -314,3 +370,30 @@ uint32_t AXP2101_getBatteryPercent(uint8_t* out_value) {
return HAL_I2C_Mem_Read(&hi2c2, AXP2101_DEV_I2C_ID, XPOWERS_AXP2101_BAT_PERCENT_DATA, 1, out_value, 1, 60);
}
xpowers_chg_status_t AXP2101_getChargerStatus(void) {
uint8_t val = 0;
int8_t status = readRegister(XPOWERS_AXP2101_STATUS2, &val, 1);
if (status == -1)
return XPOWERS_AXP2101_CHG_STOP_STATE;
val &= 0x07;
return (xpowers_chg_status_t)val;
}
uint16_t AXP2101_getBattVoltage(void) {
if (!AXP2101_isBatteryConnect()) {
return 0;
}
return readRegisterH5L8(XPOWERS_AXP2101_ADC_DATA_RELUST0, XPOWERS_AXP2101_ADC_DATA_RELUST1);
}
uint16_t AXP2101_getVbusVoltage(void) {
if (!AXP2101_isVbusIn()) {
return 0;
}
return readRegisterH6L8(XPOWERS_AXP2101_ADC_DATA_RELUST4, XPOWERS_AXP2101_ADC_DATA_RELUST5);
}
uint16_t AXP2101_getSystemVoltage(void) {
return readRegisterH6L8(XPOWERS_AXP2101_ADC_DATA_RELUST6, XPOWERS_AXP2101_ADC_DATA_RELUST7);
}

View File

@ -103,7 +103,7 @@ static const struct gpio_pin btn_pins[12] = {
static struct list_item keys_list[KEY_LIST_SIZE];
static lock_callback _lock_callback = NULL;
static key_callback _key_callback= NULL;
static uint32_t last_process_time;
static uint32_t last_process_time = 0;
static uint8_t mods[MOD_LAST];
static uint8_t capslock_changed = 0;
static uint8_t capslock = 0;
@ -281,7 +281,7 @@ static void next_item_state(struct list_item* const p_item, const uint8_t presse
break;
case KEY_STATE_PRESSED:
if (uptime_ms() > p_item->hold_start_time + hold_period) {
if (uptime_ms() - p_item->hold_start_time > hold_period) {
transition_to(p_item, KEY_STATE_HOLD);
p_item->last_repeat_time = uptime_ms();
} else if (!pressed)
@ -292,8 +292,8 @@ static void next_item_state(struct list_item* const p_item, const uint8_t presse
if (!pressed)
transition_to(p_item, KEY_STATE_RELEASED);
else {
if (uptime_ms() > p_item->hold_start_time + hold_period) {
if(uptime_ms() > p_item->last_repeat_time + KEY_REPEAT_TIME) {
if (uptime_ms() - p_item->hold_start_time > hold_period) {
if(uptime_ms() - p_item->last_repeat_time > KEY_REPEAT_TIME) {
transition_to(p_item, KEY_STATE_HOLD);
p_item->last_repeat_time = uptime_ms();
}
@ -314,7 +314,7 @@ static void next_item_state(struct list_item* const p_item, const uint8_t presse
void keyboard_process(void) {
js_bits = 0xFF;
if (uptime_ms() <= (last_process_time + reg_get_value(REG_ID_FRQ)))
if (uptime_ms() - last_process_time <= reg_get_value(REG_ID_FRQ))
return;
// Scan for columns
@ -417,6 +417,7 @@ void keyboard_process(void) {
}
io_matrix[8] = 0xFF;
last_process_time = uptime_ms();
}
last_process_time = uptime_ms();
}

View File

@ -66,9 +66,9 @@ static const uint8_t hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9
extern UART_HandleTypeDef huart3;
#endif
volatile uint32_t systicks_counter = 0; // 1 MHz systick counter - TODO: implement overflow self-reset mechanism
volatile uint32_t pmu_check_counter = 0;
volatile uint32_t i2cs_rearm_counter = 0;
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;
@ -89,12 +89,14 @@ static uint32_t pmu_online = 0;
static void key_cb(char key, enum key_state state);
static void hw_check_HP_presence(void);
static void sync_bat(void);
#ifdef DEBUG
static void printPMU(void);
#endif
static void check_pmu_int(void);
extern void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim == &htim2) {
systicks_counter += 1;
i2cs_rearm_counter += 1;
}
}
@ -111,7 +113,7 @@ extern void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirect
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 = 0;
i2cs_rearm_counter = uptime_ms();
}
}
@ -176,6 +178,10 @@ extern void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirect
i2cs_w_len = 10;
} else if (reg == REG_ID_C64_JS) {
i2cs_w_buff[1] = js_bits;
} else if (reg == REG_ID_RST) {
if (is_write)
reg_set_value(REG_ID_RST, 1);
i2cs_w_buff[1] = reg_get_value(REG_ID_RST);
} else if (reg == REG_ID_RST_PICO) {
if (is_write)
reg_set_value(REG_ID_RST_PICO, 1);
@ -196,7 +202,7 @@ extern void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirect
HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, i2cs_w_buff, i2cs_w_len, I2C_FIRST_AND_LAST_FRAME);
i2cs_rearm_counter = 0;
i2cs_rearm_counter = uptime_ms();
}
}
}
@ -307,8 +313,6 @@ int main(void) {
Error_Handler();
// Check for AXP2101 is accessible on secondary I2C bus
//result = HAL_I2C_IsDeviceReady(&hi2c2, 0x68, 3, 40);
//if (result == HAL_OK) {
result = 0;
HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_IC_TYPE, 1, (uint8_t*)&result, 1, 60);
if (result == XPOWERS_AXP2101_CHIP_ID) {
@ -402,7 +406,7 @@ int main(void) {
LL_IWDG_ReloadCounter(IWDG);
// Re-arm I2CS in case of lost master signal
if (i2cs_state != I2CS_STATE_IDLE && i2cs_rearm_counter > I2CS_REARM_TIMEOUT)
if (i2cs_state != I2CS_STATE_IDLE && ((uptime_ms() - i2cs_rearm_counter) > I2CS_REARM_TIMEOUT))
i2cs_state = I2CS_STATE_IDLE;
reg_sync();
@ -411,14 +415,23 @@ int main(void) {
hw_check_HP_presence();
// Check internal status
if (reg_get_value(REG_ID_SHTDW) == 1) {
if (reg_get_value(REG_ID_SHTDW) == 1) { // Nominal full system shutdown as requested from I2C bus
reg_set_value(REG_ID_SHTDW, 0);
LL_GPIO_ResetOutputPin(SP_AMP_EN_GPIO_Port, SP_AMP_EN_Pin);
LL_GPIO_ResetOutputPin(PICO_EN_GPIO_Port, PICO_EN_Pin);
AXP2101_setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
AXP2101_shutdown();
} else if (reg_get_value(REG_ID_RST_PICO) == 1) {
} else if (reg_get_value(REG_ID_RST) == 1) { // Try to reset only the STM32
reg_set_value(REG_ID_RST, 0);
HAL_Delay(200); // Wait for final I2C answer
if (HAL_I2C_DisableListen_IT(&hi2c1) != HAL_OK)
Error_Handler();
LL_GPIO_ResetOutputPin(SP_AMP_EN_GPIO_Port, SP_AMP_EN_Pin);
LL_GPIO_ResetOutputPin(PICO_EN_GPIO_Port, PICO_EN_Pin);
NVIC_SystemReset();
} else if (reg_get_value(REG_ID_RST_PICO) == 1) { // Reset only the Pico
reg_set_value(REG_ID_RST_PICO, 0);
HAL_Delay(200); // Wait for final I2C answer
if (HAL_I2C_DisableListen_IT(&hi2c1) != HAL_OK)
@ -538,6 +551,77 @@ __STATIC_INLINE void sync_bat(void) {
reg_set_value(REG_ID_BAT, pcnt);
}
#ifdef DEBUG
__STATIC_INLINE void printPMU(void) {
DEBUG_UART_MSG("PMU isCharging: ");
if (AXP2101_isCharging())
DEBUG_UART_MSG("YES\n\r");
else
DEBUG_UART_MSG( "NO\n\r");
DEBUG_UART_MSG("PMU isDischarge: ");
if (AXP2101_isDischarge())
DEBUG_UART_MSG("YES\n\r");
else
DEBUG_UART_MSG( "NO\n\r");
DEBUG_UART_MSG("PMU isStandby: ");
if (AXP2101_isStandby())
DEBUG_UART_MSG("YES\n\r");
else
DEBUG_UART_MSG( "NO\n\r");
DEBUG_UART_MSG("PMU isVbusIn: ");
if (AXP2101_isVbusIn())
DEBUG_UART_MSG("YES\n\r");
else
DEBUG_UART_MSG( "NO\n\r");
DEBUG_UART_MSG("PMU isVbusGood: ");
if (AXP2101_isVbusGood())
DEBUG_UART_MSG("YES\n\r");
else
DEBUG_UART_MSG( "NO\n\r");
DEBUG_UART_MSG("PMU getChargerStatus: ");
uint8_t charge_status = AXP2101_getChargerStatus();
if (charge_status == XPOWERS_AXP2101_CHG_TRI_STATE) {
DEBUG_UART_MSG("tri_charge");
} else if (charge_status == XPOWERS_AXP2101_CHG_PRE_STATE) {
DEBUG_UART_MSG("pre_charge");
} else if (charge_status == XPOWERS_AXP2101_CHG_CC_STATE) {
DEBUG_UART_MSG("constant charge");
} else if (charge_status == XPOWERS_AXP2101_CHG_CV_STATE) {
DEBUG_UART_MSG("constant voltage");
} else if (charge_status == XPOWERS_AXP2101_CHG_DONE_STATE) {
DEBUG_UART_MSG("charge done");
} else if (charge_status == XPOWERS_AXP2101_CHG_STOP_STATE) {
DEBUG_UART_MSG("not charging");
}
DEBUG_UART_MSG("PMU getBattVoltage: ");
DEBUG_UART_MSG2(AXP2101_getBattVoltage(), 2, 0);
DEBUG_UART_MSG("mV\n\r");
DEBUG_UART_MSG("PMU getVbusVoltage: ");
DEBUG_UART_MSG2(AXP2101_getVbusVoltage(), 2, 0);
DEBUG_UART_MSG("mV\n\r");
DEBUG_UART_MSG("PMU getSystemVoltage: ");
DEBUG_UART_MSG2(AXP2101_getSystemVoltage(), 2, 0);
DEBUG_UART_MSG("mV\n\r");
// The battery percentage may be inaccurate at first use, the PMU will
// automatically learn the battery curve and will automatically calibrate the
// battery percentage after a charge and discharge cycle
if (AXP2101_isBatteryConnect()) {
DEBUG_UART_MSG("PMU getBatteryPercent: ");
uint8_t pcnt = 0;
AXP2101_getBatteryPercent(&pcnt);
DEBUG_UART_MSG2(pcnt, 1, 0);
DEBUG_UART_MSG("%\n\r");
}
}
#endif
__STATIC_INLINE void check_pmu_int(void) {
if (!pmu_online)
return;
@ -636,23 +720,26 @@ __STATIC_INLINE void check_pmu_int(void) {
#endif
stop_chg();
}
if (AXP2101_isPekeyShortPressIrq()) {
#ifdef DEBUG
DEBUG_UART_MSG("PMU: isPekeyShortPress\n\r");
/*if (AXP2101_isPekeyShortPressIrq()) {
Serial1.println("isPekeyShortPress");
// enterPmuSleep();
Serial1.print("Read pmu data buffer .");
uint8_t data[4] = {0};
PMU.readDataBuffer(data, XPOWERS_AXP2101_DATA_BUFFER_SIZE);
for (int i = 0; i < 4; ++i) {
Serial1.print(data[i]);
Serial1.print(",");
}
Serial1.println();
printPMU();
}*/
uint8_t data[4] = {0};
AXP2101_readDataBuffer(data, XPOWERS_AXP2101_DATA_BUFFER_SIZE);
DEBUG_UART_MSG("PMU data buffer:\n\r");
DEBUG_UART_MSG2(data[0], 1, 0);
DEBUG_UART_MSG("\n\r");
DEBUG_UART_MSG2(data[1], 1, 0);
DEBUG_UART_MSG("\n\r");
DEBUG_UART_MSG2(data[2], 1, 0);
DEBUG_UART_MSG("\n\r");
DEBUG_UART_MSG2(data[3], 1, 0);
DEBUG_UART_MSG("\n\r");
printPMU();
#endif
// enterPmuSleep(); //TODO: implement sleep mode, RTC, etc.?
}
if (AXP2101_isPekeyLongPressIrq()) {
#ifdef DEBUG
DEBUG_UART_MSG("PMU: isPekeyLongPress\n\r");

View File

@ -110,7 +110,7 @@ uint32_t reg_check_and_save_eeprom(void) {
void reg_sync(void) {
// Save user registers in EEPROM if unsynced every 1.5s
if (uptime_ms() > (eeprom_refresh_counter + 1500)) {
if (uptime_ms() - eeprom_refresh_counter > 1500) {
reg_check_and_save_eeprom();
eeprom_refresh_counter = uptime_ms();
}

View File

@ -62,7 +62,8 @@ _Min_Stack_Size = 0x400; /* required amount of stack */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 62K
FEE (rw) : ORIGIN = 0x800F800, LENGTH = 2K
}
/* Define output sections */