Rework from official 16f241e commit
This commit is contained in:
parent
0c15c53d4d
commit
59e55fe3fe
336
Core/Inc/axp2101.h
Normal file
336
Core/Inc/axp2101.h
Normal file
@ -0,0 +1,336 @@
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
|
||||
#ifndef AXP2101_H_
|
||||
#define AXP2101_H_
|
||||
|
||||
/*
|
||||
* --------------------- I2C registers ------------------------
|
||||
*/
|
||||
#define XPOWERS_AXP2101_CHIP_ID (0x4A)
|
||||
|
||||
#define XPOWERS_AXP2101_STATUS1 (0x00)
|
||||
#define XPOWERS_AXP2101_STATUS2 (0x01)
|
||||
#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_COMMON_CONFIG (0x10)
|
||||
//#define XPOWERS_AXP2101_BATFET_CTRL (0x12)
|
||||
//#define XPOWERS_AXP2101_DIE_TEMP_CTRL (0x13)
|
||||
//#define XPOWERS_AXP2101_MIN_SYS_VOL_CTRL (0x14)
|
||||
//#define XPOWERS_AXP2101_INPUT_VOL_LIMIT_CTRL (0x15)
|
||||
//#define XPOWERS_AXP2101_INPUT_CUR_LIMIT_CTRL (0x16)
|
||||
//#define XPOWERS_AXP2101_RESET_FUEL_GAUGE (0x17)
|
||||
//#define XPOWERS_AXP2101_CHARGE_GAUGE_WDT_CTRL (0x18)
|
||||
|
||||
|
||||
//#define XPOWERS_AXP2101_WDT_CTRL (0x19)
|
||||
#define XPOWERS_AXP2101_LOW_BAT_WARN_SET (0x1A)
|
||||
|
||||
|
||||
//#define XPOWERS_AXP2101_PWRON_STATUS (0x20)
|
||||
//#define XPOWERS_AXP2101_PWROFF_STATUS (0x21)
|
||||
//#define XPOWERS_AXP2101_PWROFF_EN (0x22)
|
||||
//#define XPOWERS_AXP2101_DC_OVP_UVP_CTRL (0x23)
|
||||
#define XPOWERS_AXP2101_VOFF_SET (0x24)
|
||||
//#define XPOWERS_AXP2101_PWROK_SEQU_CTRL (0x25)
|
||||
//#define XPOWERS_AXP2101_SLEEP_WAKEUP_CTRL (0x26)
|
||||
//#define XPOWERS_AXP2101_IRQ_OFF_ON_LEVEL_CTRL (0x27)
|
||||
|
||||
//#define XPOWERS_AXP2101_FAST_PWRON_SET0 (0x28)
|
||||
//#define XPOWERS_AXP2101_FAST_PWRON_SET1 (0x29)
|
||||
//#define XPOWERS_AXP2101_FAST_PWRON_SET2 (0x2A)
|
||||
//#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)
|
||||
|
||||
/*
|
||||
* ------------------ Interrupt registers ---------------------
|
||||
*/
|
||||
#define XPOWERS_AXP2101_INTEN1 (0x40)
|
||||
#define XPOWERS_AXP2101_INTEN2 (0x41)
|
||||
#define XPOWERS_AXP2101_INTEN3 (0x42)
|
||||
|
||||
/*
|
||||
* -------------------- Status registers -----------------------
|
||||
*/
|
||||
#define XPOWERS_AXP2101_INTSTS1 (0x48)
|
||||
#define XPOWERS_AXP2101_INTSTS2 (0x49)
|
||||
#define XPOWERS_AXP2101_INTSTS3 (0x4A)
|
||||
#define XPOWERS_AXP2101_INTSTS_CNT (3)
|
||||
|
||||
#define XPOWERS_AXP2101_TS_PIN_CTRL (0x50)
|
||||
#define XPOWERS_AXP2101_TS_HYSL2H_SET (0x52)
|
||||
#define XPOWERS_AXP2101_TS_LYSL2H_SET (0x53)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_VLTF_CHG_SET (0x54)
|
||||
#define XPOWERS_AXP2101_VHLTF_CHG_SET (0x55)
|
||||
#define XPOWERS_AXP2101_VLTF_WORK_SET (0x56)
|
||||
#define XPOWERS_AXP2101_VHLTF_WORK_SET (0x57)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_JIETA_EN_CTRL (0x58)
|
||||
#define XPOWERS_AXP2101_JIETA_SET0 (0x59)
|
||||
#define XPOWERS_AXP2101_JIETA_SET1 (0x5A)
|
||||
#define XPOWERS_AXP2101_JIETA_SET2 (0x5B)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_IPRECHG_SET (0x61)
|
||||
#define XPOWERS_AXP2101_ICC_CHG_SET (0x62)
|
||||
#define XPOWERS_AXP2101_ITERM_CHG_SET_CTRL (0x63)
|
||||
|
||||
#define XPOWERS_AXP2101_CV_CHG_VOL_SET (0x64)
|
||||
|
||||
#define XPOWERS_AXP2101_THE_REGU_THRES_SET (0x65)
|
||||
#define XPOWERS_AXP2101_CHG_TIMEOUT_SET_CTRL (0x67)
|
||||
|
||||
#define XPOWERS_AXP2101_BAT_DET_CTRL (0x68)
|
||||
#define XPOWERS_AXP2101_CHGLED_SET_CTRL (0x69)
|
||||
|
||||
#define XPOWERS_AXP2101_BTN_VOL_MIN (2600)
|
||||
#define XPOWERS_AXP2101_BTN_VOL_MAX (3300)
|
||||
#define XPOWERS_AXP2101_BTN_VOL_STEPS (100)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_BTN_BAT_CHG_VOL_SET (0x6A)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_DC_ONOFF_DVM_CTRL (0x80)
|
||||
#define XPOWERS_AXP2101_DC_FORCE_PWM_CTRL (0x81)
|
||||
#define XPOWERS_AXP2101_DC_VOL0_CTRL (0x82)
|
||||
#define XPOWERS_AXP2101_DC_VOL1_CTRL (0x83)
|
||||
#define XPOWERS_AXP2101_DC_VOL2_CTRL (0x84)
|
||||
#define XPOWERS_AXP2101_DC_VOL3_CTRL (0x85)
|
||||
#define XPOWERS_AXP2101_DC_VOL4_CTRL (0x86)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_LDO_ONOFF_CTRL0 (0x90)
|
||||
#define XPOWERS_AXP2101_LDO_ONOFF_CTRL1 (0x91)
|
||||
#define XPOWERS_AXP2101_LDO_VOL0_CTRL (0x92)
|
||||
#define XPOWERS_AXP2101_LDO_VOL1_CTRL (0x93)
|
||||
#define XPOWERS_AXP2101_LDO_VOL2_CTRL (0x94)
|
||||
#define XPOWERS_AXP2101_LDO_VOL3_CTRL (0x95)
|
||||
#define XPOWERS_AXP2101_LDO_VOL4_CTRL (0x96)
|
||||
#define XPOWERS_AXP2101_LDO_VOL5_CTRL (0x97)
|
||||
#define XPOWERS_AXP2101_LDO_VOL6_CTRL (0x98)
|
||||
#define XPOWERS_AXP2101_LDO_VOL7_CTRL (0x99)
|
||||
#define XPOWERS_AXP2101_LDO_VOL8_CTRL (0x9A)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_BAT_PARAME (0xA1)
|
||||
#define XPOWERS_AXP2101_FUEL_GAUGE_CTRL (0xA2)
|
||||
#define XPOWERS_AXP2101_BAT_PERCENT_DATA (0xA4)
|
||||
|
||||
/*
|
||||
* ------------------------ DCDC 1~5 ---------------------------
|
||||
*/
|
||||
#define XPOWERS_AXP2101_DCDC1_VOL_MIN (1500)
|
||||
#define XPOWERS_AXP2101_DCDC1_VOL_MAX (3400)
|
||||
#define XPOWERS_AXP2101_DCDC1_VOL_STEPS (100u)
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC2_VOL1_MIN (500u)
|
||||
#define XPOWERS_AXP2101_DCDC2_VOL1_MAX (1200u)
|
||||
#define XPOWERS_AXP2101_DCDC2_VOL2_MIN (1220u)
|
||||
#define XPOWERS_AXP2101_DCDC2_VOL2_MAX (1540u)
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC2_VOL_STEPS1 (10u)
|
||||
#define XPOWERS_AXP2101_DCDC2_VOL_STEPS2 (20u)
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC2_VOL_STEPS1_BASE (0u)
|
||||
#define XPOWERS_AXP2101_DCDC2_VOL_STEPS2_BASE (71)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL1_MIN (500u)
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL1_MAX (1200u)
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL2_MIN (1220u)
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL2_MAX (1540u)
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL3_MIN (1600u)
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL3_MAX (3400u)
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL_MIN (500)
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL_MAX (3400)
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL_STEPS1 (10u)
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL_STEPS2 (20u)
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL_STEPS3 (100u)
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL_STEPS1_BASE (0u)
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL_STEPS2_BASE (71)
|
||||
#define XPOWERS_AXP2101_DCDC3_VOL_STEPS3_BASE (88)
|
||||
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC4_VOL1_MIN (500u)
|
||||
#define XPOWERS_AXP2101_DCDC4_VOL1_MAX (1200u)
|
||||
#define XPOWERS_AXP2101_DCDC4_VOL2_MIN (1220u)
|
||||
#define XPOWERS_AXP2101_DCDC4_VOL2_MAX (1840u)
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC4_VOL_STEPS1 (10u)
|
||||
#define XPOWERS_AXP2101_DCDC4_VOL_STEPS2 (20u)
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC4_VOL_STEPS1_BASE (0u)
|
||||
#define XPOWERS_AXP2101_DCDC4_VOL_STEPS2_BASE (71)
|
||||
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_DCDC5_VOL_1200MV (1200)
|
||||
#define XPOWERS_AXP2101_DCDC5_VOL_VAL (0x19)
|
||||
#define XPOWERS_AXP2101_DCDC5_VOL_MIN (1400)
|
||||
#define XPOWERS_AXP2101_DCDC5_VOL_MAX (3700)
|
||||
#define XPOWERS_AXP2101_DCDC5_VOL_STEPS (100u)
|
||||
|
||||
#define XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_MIN (2600)
|
||||
#define XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_MAX (3300)
|
||||
#define XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_STEPS (100)
|
||||
|
||||
/*
|
||||
* ----------------------- ALDO 1~4 --------------------------
|
||||
*/
|
||||
#define XPOWERS_AXP2101_ALDO1_VOL_MIN (500)
|
||||
#define XPOWERS_AXP2101_ALDO1_VOL_MAX (3500)
|
||||
#define XPOWERS_AXP2101_ALDO1_VOL_STEPS (100u)
|
||||
|
||||
#define XPOWERS_AXP2101_ALDO2_VOL_MIN (500)
|
||||
#define XPOWERS_AXP2101_ALDO2_VOL_MAX (3500)
|
||||
#define XPOWERS_AXP2101_ALDO2_VOL_STEPS (100u)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_ALDO3_VOL_MIN (500)
|
||||
#define XPOWERS_AXP2101_ALDO3_VOL_MAX (3500)
|
||||
#define XPOWERS_AXP2101_ALDO3_VOL_STEPS (100u)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_ALDO4_VOL_MIN (500)
|
||||
#define XPOWERS_AXP2101_ALDO4_VOL_MAX (3500)
|
||||
#define XPOWERS_AXP2101_ALDO4_VOL_STEPS (100u)
|
||||
|
||||
/*
|
||||
* ----------------------- BLDO 1~2 --------------------------
|
||||
*/
|
||||
#define XPOWERS_AXP2101_BLDO1_VOL_MIN (500)
|
||||
#define XPOWERS_AXP2101_BLDO1_VOL_MAX (3500)
|
||||
#define XPOWERS_AXP2101_BLDO1_VOL_STEPS (100u)
|
||||
|
||||
#define XPOWERS_AXP2101_BLDO2_VOL_MIN (500)
|
||||
#define XPOWERS_AXP2101_BLDO2_VOL_MAX (3500)
|
||||
#define XPOWERS_AXP2101_BLDO2_VOL_STEPS (100u)
|
||||
|
||||
/*
|
||||
* ----------------------- CPUSLDO --------------------------
|
||||
*/
|
||||
#define XPOWERS_AXP2101_CPUSLDO_VOL_MIN (500)
|
||||
#define XPOWERS_AXP2101_CPUSLDO_VOL_MAX (1400)
|
||||
#define XPOWERS_AXP2101_CPUSLDO_VOL_STEPS (50)
|
||||
|
||||
|
||||
/*
|
||||
* ----------------------- DLDO 1~2 --------------------------
|
||||
*/
|
||||
#define XPOWERS_AXP2101_DLDO1_VOL_MIN (500)
|
||||
#define XPOWERS_AXP2101_DLDO1_VOL_MAX (3400)
|
||||
#define XPOWERS_AXP2101_DLDO1_VOL_STEPS (100u)
|
||||
|
||||
#define XPOWERS_AXP2101_DLDO2_VOL_MIN (500)
|
||||
#define XPOWERS_AXP2101_DLDO2_VOL_MAX (3400)
|
||||
#define XPOWERS_AXP2101_DLDO2_VOL_STEPS (100u)
|
||||
|
||||
|
||||
#define XPOWERS_AXP2101_CONVERSION(raw) (22.0 + (7274 - raw) / 20.0)
|
||||
#define _BV(b) (1UL << (uint32_t)(b))
|
||||
|
||||
/**
|
||||
* @brief Charging led mode parameters.
|
||||
*/
|
||||
typedef enum __xpowers_chg_led_mode {
|
||||
XPOWERS_CHG_LED_OFF,
|
||||
XPOWERS_CHG_LED_BLINK_1HZ,
|
||||
XPOWERS_CHG_LED_BLINK_4HZ,
|
||||
XPOWERS_CHG_LED_ON,
|
||||
XPOWERS_CHG_LED_CTRL_CHG, // The charging indicator is controlled by the charger
|
||||
} xpowers_chg_led_mode_t;
|
||||
|
||||
/**
|
||||
* @brief axp2101 interrupt control mask parameters.
|
||||
*/
|
||||
typedef enum __xpowers_axp2101_irq {
|
||||
//! IRQ1 REG 40H
|
||||
XPOWERS_AXP2101_BAT_NOR_UNDER_TEMP_IRQ = _BV(0), // Battery Under Temperature in Work
|
||||
XPOWERS_AXP2101_BAT_NOR_OVER_TEMP_IRQ = _BV(1), // Battery Over Temperature in Work mode
|
||||
XPOWERS_AXP2101_BAT_CHG_UNDER_TEMP_IRQ = _BV(2), // Battery Under Temperature in Charge mode IRQ(bcut_irq)
|
||||
XPOWERS_AXP2101_BAT_CHG_OVER_TEMP_IRQ = _BV(3), // Battery Over Temperature in Charge mode IRQ(bcot_irq) enable
|
||||
XPOWERS_AXP2101_GAUGE_NEW_SOC_IRQ = _BV(4), // Gauge New SOC IRQ(lowsoc_irq) enable ???
|
||||
XPOWERS_AXP2101_WDT_TIMEOUT_IRQ = _BV(5), // Gauge Watchdog Timeout IRQ(gwdt_irq) enable
|
||||
XPOWERS_AXP2101_WARNING_LEVEL1_IRQ = _BV(6), // SOC drop to Warning Level1 IRQ(socwl1_irq) enable
|
||||
XPOWERS_AXP2101_WARNING_LEVEL2_IRQ = _BV(7), // SOC drop to Warning Level2 IRQ(socwl2_irq) enable
|
||||
|
||||
//! IRQ2 REG 41H
|
||||
XPOWERS_AXP2101_PKEY_POSITIVE_IRQ = _BV(8), // POWERON Positive Edge IRQ(ponpe_irq_en) enable
|
||||
XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ = _BV(9), // POWERON Negative Edge IRQ(ponne_irq_en) enable
|
||||
XPOWERS_AXP2101_PKEY_LONG_IRQ = _BV(10), // POWERON Long PRESS IRQ(ponlp_irq) enable
|
||||
XPOWERS_AXP2101_PKEY_SHORT_IRQ = _BV(11), // POWERON Short PRESS IRQ(ponsp_irq_en) enable
|
||||
XPOWERS_AXP2101_BAT_REMOVE_IRQ = _BV(12), // Battery Remove IRQ(bremove_irq) enable
|
||||
XPOWERS_AXP2101_BAT_INSERT_IRQ = _BV(13), // Battery Insert IRQ(binsert_irq) enabl
|
||||
XPOWERS_AXP2101_VBUS_REMOVE_IRQ = _BV(14), // VBUS Remove IRQ(vremove_irq) enabl
|
||||
XPOWERS_AXP2101_VBUS_INSERT_IRQ = _BV(15), // VBUS Insert IRQ(vinsert_irq) enable
|
||||
|
||||
//! IRQ3 REG 42H
|
||||
XPOWERS_AXP2101_BAT_OVER_VOL_IRQ = _BV(16), // Battery Over Voltage Protection IRQ(bovp_irq) enable
|
||||
XPOWERS_AXP2101_CHAGER_TIMER_IRQ = _BV(17), // Charger Safety Timer1/2 expire IRQ(chgte_irq) enable
|
||||
XPOWERS_AXP2101_DIE_OVER_TEMP_IRQ = _BV(18), // DIE Over Temperature level1 IRQ(dotl1_irq) enable
|
||||
XPOWERS_AXP2101_BAT_CHG_START_IRQ = _BV(19), // Charger start IRQ(chgst_irq) enable
|
||||
XPOWERS_AXP2101_BAT_CHG_DONE_IRQ = _BV(20), // Battery charge done IRQ(chgdn_irq) enable
|
||||
XPOWERS_AXP2101_BATFET_OVER_CURR_IRQ = _BV(21), // BATFET Over Current Protection IRQ(bocp_irq) enable
|
||||
XPOWERS_AXP2101_LDO_OVER_CURR_IRQ = _BV(22), // LDO Over Current IRQ(ldooc_irq) enable
|
||||
XPOWERS_AXP2101_WDT_EXPIRE_IRQ = _BV(23), // Watchdog Expire IRQ(wdexp_irq) enable
|
||||
|
||||
XPOWERS_AXP2101_ALL_IRQ = (0xFFFFFFFFUL)
|
||||
} xpowers_axp2101_irq_t;
|
||||
|
||||
|
||||
uint32_t AXP2101_shutdown(void);
|
||||
uint32_t AXP2101_disableTSPinMeasure(void);
|
||||
uint32_t AXP2101_enableBattDetection(void);
|
||||
uint32_t AXP2101_enableBattVoltageMeasure(void);
|
||||
uint32_t AXP2101_enableSystemVoltageMeasure(void);
|
||||
uint32_t AXP2101_enableVbusVoltageMeasure(void);
|
||||
uint32_t AXP2101_enableIRQ(uint32_t opt);
|
||||
uint32_t AXP2101_disableIRQ(uint32_t opt);
|
||||
uint32_t AXP2101_clearIrqStatus(void);
|
||||
|
||||
uint8_t AXP2101_isDropWarningLevel1Irq(void);
|
||||
uint8_t AXP2101_isVbusRemoveIrq(void);
|
||||
uint8_t AXP2101_isBatInsertIrq(void);
|
||||
uint8_t AXP2101_isBatRemoveIrq(void);
|
||||
uint8_t AXP2101_isPekeyShortPressIrq(void);
|
||||
uint8_t AXP2101_isPekeyLongPressIrq(void);
|
||||
uint8_t AXP2101_isBatChargeDoneIrq(void);
|
||||
uint8_t AXP2101_isBatChargeStartIrq(void);
|
||||
|
||||
uint32_t AXP2101_setLowBatWarnThreshold(uint8_t percentage);
|
||||
uint32_t AXP2101_setLowBatShutdownThreshold(uint8_t opt);
|
||||
uint32_t AXP2101_setSysPowerDownVoltage(uint16_t value);
|
||||
uint32_t AXP2101_setChargingLedMode(uint8_t mode);
|
||||
|
||||
uint8_t AXP2101_isBatteryConnect(void);
|
||||
uint8_t AXP2101_isCharging(void);
|
||||
uint32_t AXP2101_getIrqStatus(uint32_t* out_value);
|
||||
uint32_t AXP2101_getBatteryPercent(uint8_t* out_value);
|
||||
|
||||
#endif /* AXP2101_H_ */
|
19
Core/Inc/backlight.h
Normal file
19
Core/Inc/backlight.h
Normal file
@ -0,0 +1,19 @@
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
|
||||
#ifndef BACKLIGHT_H_
|
||||
#define BACKLIGHT_H_
|
||||
|
||||
void lcd_backlight_update_from_reg(void);
|
||||
void lcd_backlight_on(void);
|
||||
void lcd_backlight_off(void);
|
||||
void lcd_backlight_update(uint8_t step);
|
||||
void lcd_backlight_update_up(void);
|
||||
void lcd_backlight_update_down(void);
|
||||
|
||||
void kbd_backlight_on(void);
|
||||
void kbd_backlight_off(void);
|
||||
void kbd_backlight_update(uint8_t step);
|
||||
void kbd_backlight_update_loop(void);
|
||||
|
||||
#endif /* BACKLIGHT_H_ */
|
18
Core/Inc/batt.h
Normal file
18
Core/Inc/batt.h
Normal file
@ -0,0 +1,18 @@
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
|
||||
#ifndef BATT_H_
|
||||
#define BATT_H_
|
||||
|
||||
|
||||
#define LOW_BAT_VAL (20)
|
||||
|
||||
|
||||
void show_bat_segs(void);
|
||||
|
||||
void low_bat(void);
|
||||
|
||||
void start_chg(void);
|
||||
void stop_chg(void);
|
||||
|
||||
#endif /* BATT_H_ */
|
87
Core/Inc/eeprom.h
Normal file
87
Core/Inc/eeprom.h
Normal file
@ -0,0 +1,87 @@
|
||||
//EEPROM emulation library for STM32F1XX with HAL-Driver
|
||||
//V2.0
|
||||
|
||||
|
||||
//define to prevent recursive inclusion
|
||||
#ifndef __EEPROM_H
|
||||
#define __EEPROM_H
|
||||
|
||||
//includes
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
//-------------------------------------------library configuration-------------------------------------------
|
||||
|
||||
//number of variables (maximum variable name is EEPROM_VARIABLE_COUNT - 1)
|
||||
//keep in mind it is limited by page size
|
||||
//maximum is also determined by your variable sizes
|
||||
//space utilization ratio X = (2 + 4*COUNT_16BIT + 6*COUNT_32BIT + 10*COUNT_64BIT) / PAGE_SIZE
|
||||
//if X is high, variable changes more often require a page transfer --> lifetime of the flash can be reduced significantly
|
||||
//depending on your variable change rate, X should be at least <50%
|
||||
#define EEPROM_VARIABLE_COUNT (uint16_t) 4
|
||||
|
||||
//flash size of used STM32F1XX device in KByte
|
||||
#define EEPROM_FLASH_SIZE (uint16_t) 64
|
||||
|
||||
//-------------------------------------------------constants-------------------------------------------------
|
||||
|
||||
//EEPROM emulation start address in flash: use last two pages of flash memory
|
||||
#define EEPROM_START_ADDRESS (uint32_t) (0x08000000 + 1024*EEPROM_FLASH_SIZE - 2*FLASH_PAGE_SIZE)
|
||||
|
||||
//used flash pages for EEPROM emulation
|
||||
typedef enum
|
||||
{
|
||||
EEPROM_PAGE0 = EEPROM_START_ADDRESS, //Page0
|
||||
EEPROM_PAGE1 = EEPROM_START_ADDRESS + FLASH_PAGE_SIZE, //Page1
|
||||
EEPROM_PAGE_NONE = 0x00000000 //no page
|
||||
} EEPROM_Page;
|
||||
|
||||
//page status
|
||||
typedef enum
|
||||
{
|
||||
EEPROM_ERASED = 0xFFFF, //Page is empty
|
||||
EEPROM_RECEIVING = 0xEEEE, //Page is marked to receive data
|
||||
EEPROM_VALID = 0x0000 //Page containing valid data
|
||||
} EEPROM_PageStatus;
|
||||
|
||||
//results
|
||||
typedef enum
|
||||
{
|
||||
EEPROM_SUCCESS = 0x00, //Method successful / HAL_OK
|
||||
EEPROM_ERROR = 0x01, //Error: HAL_ERROR occurred
|
||||
EEPROM_BUSY = 0x02, //Error: HAL_BUSY occurred
|
||||
EEPROM_TIMEOUT = 0x03, //Error: HAL_TIMEOUT occurred
|
||||
EEPROM_NO_VALID_PAGE = 0x04, //Error: no valid page found
|
||||
EEPROM_NOT_ASSIGNED = 0x05, //Error: variable was never assigned
|
||||
EEPROM_INVALID_NAME = 0x06, //Error: variable name to high for variable count
|
||||
EEPROM_FULL = 0x07 //Error: EEPROM is full
|
||||
} EEPROM_Result;
|
||||
|
||||
//sizes ( halfwords = 2 ^ (size-1) )
|
||||
typedef enum
|
||||
{
|
||||
EEPROM_SIZE_DELETED = 0x00, //variable is deleted (no size)
|
||||
EEPROM_SIZE16 = 0x01, //variable size = 16 bit = 1 Halfword
|
||||
EEPROM_SIZE32 = 0x02, //variable size = 32 bit = 2 Halfwords
|
||||
EEPROM_SIZE64 = 0x03 //variable size = 64 bit = 4 Halfwords
|
||||
} EEPROM_Size;
|
||||
|
||||
typedef union
|
||||
{
|
||||
int16_t Int16;
|
||||
int32_t Int32;
|
||||
int64_t Int64;
|
||||
uint16_t uInt16;
|
||||
uint32_t uInt32;
|
||||
uint64_t uInt64;
|
||||
float Float;
|
||||
double Double;
|
||||
} EEPROM_Value;
|
||||
|
||||
//----------------------------------------------public functions---------------------------------------------
|
||||
|
||||
EEPROM_Result EEPROM_Init();
|
||||
EEPROM_Result EEPROM_ReadVariable(uint16_t VariableName, EEPROM_Value* Value);
|
||||
EEPROM_Result EEPROM_WriteVariable(uint16_t VariableName, EEPROM_Value Value, EEPROM_Size Size);
|
||||
EEPROM_Result EEPROM_DeleteVariable(uint16_t VariableName);
|
||||
|
||||
#endif
|
22
Core/Inc/fifo.h
Normal file
22
Core/Inc/fifo.h
Normal file
@ -0,0 +1,22 @@
|
||||
#include "stm32f1xx_hal.h"
|
||||
#include "keyboard.h"
|
||||
|
||||
|
||||
#ifndef FIFO_H_
|
||||
#define FIFO_H_
|
||||
|
||||
#define FIFO_SIZE 31
|
||||
|
||||
struct fifo_item {
|
||||
uint8_t key;
|
||||
enum key_state state;
|
||||
};
|
||||
|
||||
|
||||
uint8_t fifo_count(void);
|
||||
void fifo_flush(void);
|
||||
uint8_t fifo_enqueue(const struct fifo_item item);
|
||||
void fifo_enqueue_force(const struct fifo_item item);
|
||||
void fifo_dequeue(struct fifo_item* const outItem);
|
||||
|
||||
#endif /* FIFO_H_ */
|
92
Core/Inc/keyboard.h
Normal file
92
Core/Inc/keyboard.h
Normal file
@ -0,0 +1,92 @@
|
||||
#include "stm32f1xx_hal.h"
|
||||
#include "main.h"
|
||||
|
||||
#ifndef KEYBOARD_H_
|
||||
#define KEYBOARD_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum key_state {
|
||||
KEY_STATE_IDLE = 0,
|
||||
KEY_STATE_PRESSED,
|
||||
KEY_STATE_HOLD,
|
||||
KEY_STATE_RELEASED,
|
||||
};
|
||||
|
||||
#define NUM_OF_COLS 8
|
||||
#define NUM_OF_ROWS 7
|
||||
|
||||
#define KEY_LIST_SIZE 10
|
||||
|
||||
#define KEY_POLL_TIME 16 // in ms, scanning freq
|
||||
#define KEY_HOLD_TIME 300 // in ms, delay before switching to "rapid-trigger" mode
|
||||
#define KEY_REPEAT_TIME 100 // in ms, delay between each triggers in "rapid-trigger" mode
|
||||
|
||||
#define KEY_JOY_UP 0x01
|
||||
#define KEY_JOY_DOWN 0x02
|
||||
#define KEY_JOY_LEFT 0x03
|
||||
#define KEY_JOY_RIGHT 0x04
|
||||
#define KEY_JOY_CENTER 0x05
|
||||
#define KEY_BTN_LEFT1 0x06
|
||||
#define KEY_BTN_RIGHT1 0x07
|
||||
|
||||
#define KEY_BACKSPACE 0x08
|
||||
#define KEY_TAB 0x09
|
||||
#define KEY_ENTER 0x0A
|
||||
// 0x0D - CARRIAGE RETURN
|
||||
#define KEY_BTN_LEFT2 0x11
|
||||
#define KEY_BTN_RIGHT2 0x12
|
||||
|
||||
|
||||
#define KEY_MOD_ALT 0xA1
|
||||
#define KEY_MOD_SHL 0xA2
|
||||
#define KEY_MOD_SHR 0xA3
|
||||
#define KEY_MOD_SYM 0xA4
|
||||
#define KEY_MOD_CTRL 0xA5
|
||||
|
||||
#define KEY_ESC 0xB1
|
||||
#define KEY_UP 0xb5
|
||||
#define KEY_DOWN 0xb6
|
||||
#define KEY_LEFT 0xb4
|
||||
#define KEY_RIGHT 0xb7
|
||||
|
||||
#define KEY_BREAK 0xd0 // == KEY_PAUSE
|
||||
#define KEY_INSERT 0xD1
|
||||
#define KEY_HOME 0xD2
|
||||
#define KEY_DEL 0xD4
|
||||
#define KEY_END 0xD5
|
||||
#define KEY_PAGE_UP 0xd6
|
||||
#define KEY_PAGE_DOWN 0xd7
|
||||
|
||||
#define KEY_CAPS_LOCK 0xC1
|
||||
|
||||
#define KEY_F1 0x81
|
||||
#define KEY_F2 0x82
|
||||
#define KEY_F3 0x83
|
||||
#define KEY_F4 0x84
|
||||
#define KEY_F5 0x85
|
||||
#define KEY_F6 0x86
|
||||
#define KEY_F7 0x87
|
||||
#define KEY_F8 0x88
|
||||
#define KEY_F9 0x89
|
||||
#define KEY_F10 0x90
|
||||
|
||||
|
||||
typedef void (*key_callback)(char, enum key_state);
|
||||
typedef void (*lock_callback)(uint8_t, uint8_t);
|
||||
|
||||
|
||||
void keyboard_set_key_callback(key_callback callback);
|
||||
void keyboard_set_lock_callback(lock_callback callback);
|
||||
uint8_t keyboard_get_capslock(void);
|
||||
uint8_t keyboard_get_numlock(void);
|
||||
void keyboard_process(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* KEYBOARD_H_ */
|
@ -1,18 +1,12 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : main.h
|
||||
* @brief : Header for main.c file.
|
||||
* This file contains the common defines of the application.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* Copyright (c) 2025 C.ARE (JackCarterSmith).
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
@ -42,7 +36,7 @@ extern "C" {
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
#include "stm32f1xx_ll_tim.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
@ -52,7 +46,14 @@ extern "C" {
|
||||
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
/* USER CODE BEGIN EC */
|
||||
extern TIM_HandleTypeDef htim1;
|
||||
extern TIM_HandleTypeDef htim3;
|
||||
extern I2C_HandleTypeDef hi2c2;
|
||||
|
||||
extern volatile uint32_t systicks_counter;
|
||||
extern volatile uint8_t pmu_irq;
|
||||
extern uint8_t io_matrix[9];
|
||||
extern uint8_t js_bits;
|
||||
/* USER CODE END EC */
|
||||
|
||||
/* Exported macro ------------------------------------------------------------*/
|
||||
@ -66,7 +67,9 @@ void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
|
||||
void Error_Handler(void);
|
||||
|
||||
/* USER CODE BEGIN EFP */
|
||||
__STATIC_INLINE uint32_t uptime_ms(void) { return systicks_counter; }
|
||||
|
||||
void flash_one_time(uint32_t ts, uint8_t restore_status);
|
||||
/* USER CODE END EFP */
|
||||
|
||||
/* Private defines -----------------------------------------------------------*/
|
||||
@ -155,7 +158,10 @@ void Error_Handler(void);
|
||||
#define PICO_SDA_GPIO_Port GPIOB
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
#define EEPROM_VAR_ID (0) // 16b: Init ID: 0xCA1C
|
||||
#define EEPROM_VAR_CFG (1) // 16b: 0x00 + CFG reg
|
||||
#define EEPROM_VAR_KBD (2) // 16b: DEB + FRQ regs
|
||||
#define EEPROM_VAR_BCKL (3) // 16b: LCD + KBD backlight step indice
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
57
Core/Inc/regs.h
Normal file
57
Core/Inc/regs.h
Normal file
@ -0,0 +1,57 @@
|
||||
#include "stm32f1xx_hal.h"
|
||||
|
||||
|
||||
#ifndef REGS_H_
|
||||
#define REGS_H_
|
||||
|
||||
enum reg_id
|
||||
{
|
||||
REG_ID_VER = 0x01, // fw version
|
||||
REG_ID_CFG = 0x02, // config
|
||||
REG_ID_INT = 0x03, // interrupt status
|
||||
REG_ID_KEY = 0x04, // key status
|
||||
REG_ID_BKL = 0x05, // backlight steps (0-9)
|
||||
REG_ID_DEB = 0x06, // debounce cfg
|
||||
REG_ID_FRQ = 0x07, // poll freq cfg
|
||||
REG_ID_RST = 0x08, // reset
|
||||
REG_ID_FIF = 0x09, // fifo
|
||||
REG_ID_BK2 = 0x0A, // keyboard backlight (0-9)
|
||||
REG_ID_BAT = 0x0B, // battery
|
||||
REG_ID_C64_MTX = 0x0C,// read c64 matrix
|
||||
REG_ID_C64_JS = 0x0D, // joystick io bits
|
||||
REG_ID_LAST,
|
||||
};
|
||||
|
||||
#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_INT (1 << 1) //Should an interrupt be generated when a FIFO overflow happens
|
||||
#define CFG_CAPSLOCK_INT (1 << 2) //Should an interrupt be generated when Caps Lock is toggled.
|
||||
#define CFG_NUMLOCK_INT (1 << 3) //Should an interrupt be generated when Num Lock is toggled.
|
||||
#define CFG_KEY_INT (1 << 4)
|
||||
#define CFG_PANIC_INT (1 << 5)
|
||||
#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
|
||||
// CFG_STICKY_MODS // Pressing and releasing a mod affects next key pressed
|
||||
|
||||
#define INT_OVERFLOW (1 << 0)
|
||||
#define INT_CAPSLOCK (1 << 1)
|
||||
#define INT_NUMLOCK (1 << 2)
|
||||
#define INT_KEY (1 << 3)
|
||||
#define INT_PANIC (1 << 4)
|
||||
|
||||
#define KEY_CAPSLOCK (1 << 5)
|
||||
#define KEY_NUMLOCK (1 << 6)
|
||||
#define KEY_COUNT_MASK 0x1F //0x1F == 31
|
||||
|
||||
//#define VER_VAL ((VERSION_MAJOR << 4) | (VERSION_MINOR << 0))
|
||||
|
||||
|
||||
uint8_t reg_get_value(enum reg_id reg);
|
||||
uint8_t* reg_raw_access(void);
|
||||
void reg_set_value(enum reg_id reg, uint8_t value);
|
||||
uint8_t reg_is_bit_set(enum reg_id reg, uint8_t bit);
|
||||
void reg_set_bit(enum reg_id reg, uint8_t bit);
|
||||
void reg_init(void);
|
||||
uint32_t reg_check_and_save_eeprom(void);
|
||||
void reg_sync(void);
|
||||
|
||||
#endif /* REGS_H_ */
|
311
Core/Src/axp2101.c
Normal file
311
Core/Src/axp2101.c
Normal file
@ -0,0 +1,311 @@
|
||||
#include "axp2101.h"
|
||||
#include "main.h"
|
||||
#include "stm32_assert.h"
|
||||
|
||||
|
||||
static uint8_t statusRegister[XPOWERS_AXP2101_INTSTS_CNT] = {0};
|
||||
static uint8_t intRegister[XPOWERS_AXP2101_INTSTS_CNT] = {0};
|
||||
|
||||
|
||||
__STATIC_INLINE uint8_t clrRegisterBit(uint8_t registers, uint8_t bit) {
|
||||
uint8_t reg_value = 0;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
status = HAL_I2C_Mem_Read(&hi2c2, 0x68, registers, 1, ®_value, 1, 60);
|
||||
if (status != HAL_OK)
|
||||
return 1;
|
||||
|
||||
reg_value &= (uint8_t)(~_BV(bit));
|
||||
return HAL_I2C_Mem_Write(&hi2c2, 0x68, registers, 1, ®_value, 1, 60);
|
||||
}
|
||||
|
||||
__STATIC_INLINE uint8_t getRegisterBit(uint8_t registers, uint8_t bit) {
|
||||
uint8_t reg_value = 0;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
status = HAL_I2C_Mem_Read(&hi2c2, 0x68, registers, 1, ®_value, 1, 60);
|
||||
if (status != HAL_OK)
|
||||
return 1;
|
||||
|
||||
return reg_value & _BV(bit);
|
||||
}
|
||||
|
||||
__STATIC_INLINE uint8_t setRegisterBit(uint8_t registers, uint8_t bit) {
|
||||
uint8_t reg_value = 0;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
status = HAL_I2C_Mem_Read(&hi2c2, 0x68, registers, 1, ®_value, 1, 60);
|
||||
if (status != HAL_OK)
|
||||
return 1;
|
||||
|
||||
reg_value |= (uint8_t)(_BV(bit));
|
||||
return HAL_I2C_Mem_Write(&hi2c2, 0x68, registers, 1, ®_value, 1, 60);
|
||||
}
|
||||
|
||||
uint32_t setInterruptImpl(uint32_t opts, uint8_t enable) {
|
||||
uint8_t reg_value = 0;
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
|
||||
if (opts & 0x0000FF) {
|
||||
HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_INTEN1, 1, ®_value, 1, 60);
|
||||
intRegister[0] = enable ? (uint8_t)(reg_value | (opts & 0xFF)) : (uint8_t)(reg_value & (~(opts & 0xFF)));
|
||||
status |= HAL_I2C_Mem_Write(&hi2c2, 0x68, XPOWERS_AXP2101_INTEN1, 1, &intRegister[0], 1, 60);
|
||||
}
|
||||
if (opts & 0x00FF00) {
|
||||
HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_INTEN2, 1, ®_value, 1, 60);
|
||||
intRegister[1] = enable ? (uint8_t)(reg_value | (opts >> 8)) : (uint8_t)(reg_value & (~(opts >> 8)));
|
||||
status |= HAL_I2C_Mem_Write(&hi2c2, 0x68, XPOWERS_AXP2101_INTEN2, 1, &intRegister[1], 1, 60);
|
||||
}
|
||||
if (opts & 0xFF0000) {
|
||||
HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_INTEN3, 1, ®_value, 1, 60);
|
||||
intRegister[2] = enable ? (uint8_t)(reg_value | (opts >> 16)) : (uint8_t)(reg_value & (~(opts >> 16)));
|
||||
status |= HAL_I2C_Mem_Write(&hi2c2, 0x68, XPOWERS_AXP2101_INTEN3, 1, &intRegister[2], 1, 60);
|
||||
}
|
||||
|
||||
return (uint32_t)status;
|
||||
}
|
||||
|
||||
|
||||
uint32_t AXP2101_shutdown(void) {
|
||||
return setRegisterBit(XPOWERS_AXP2101_COMMON_CONFIG, 0);
|
||||
}
|
||||
|
||||
uint32_t AXP2101_disableTSPinMeasure(void) {
|
||||
return clrRegisterBit(XPOWERS_AXP2101_ADC_CHANNEL_CTRL, 1);
|
||||
}
|
||||
|
||||
uint32_t AXP2101_enableBattDetection(void) {
|
||||
return setRegisterBit(XPOWERS_AXP2101_BAT_DET_CTRL, 0);
|
||||
}
|
||||
|
||||
uint32_t AXP2101_enableBattVoltageMeasure(void) {
|
||||
return setRegisterBit(XPOWERS_AXP2101_ADC_CHANNEL_CTRL, 0);
|
||||
}
|
||||
|
||||
uint32_t AXP2101_enableSystemVoltageMeasure(void) {
|
||||
return setRegisterBit(XPOWERS_AXP2101_ADC_CHANNEL_CTRL, 3);
|
||||
}
|
||||
|
||||
uint32_t AXP2101_enableVbusVoltageMeasure(void) {
|
||||
return setRegisterBit(XPOWERS_AXP2101_ADC_CHANNEL_CTRL, 2);
|
||||
}
|
||||
|
||||
uint32_t AXP2101_enableIRQ(uint32_t opt) {
|
||||
return setInterruptImpl(opt, 1);
|
||||
}
|
||||
|
||||
uint32_t AXP2101_disableIRQ(uint32_t opt) {
|
||||
return setInterruptImpl(opt, 0);
|
||||
}
|
||||
|
||||
uint32_t AXP2101_clearIrqStatus(void) {
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
uint8_t fbuff = 0xFF;
|
||||
|
||||
for (size_t i = 0; i < XPOWERS_AXP2101_INTSTS_CNT; i++) {
|
||||
status |= HAL_I2C_Mem_Write(&hi2c2, 0x68, XPOWERS_AXP2101_INTSTS1 + (uint8_t)i, 1, &fbuff, 1, 60);
|
||||
statusRegister[i] = 0;
|
||||
}
|
||||
|
||||
return (uint32_t)status;
|
||||
}
|
||||
|
||||
uint8_t AXP2101_isDropWarningLevel1Irq(void) {
|
||||
uint8_t mask = XPOWERS_AXP2101_WARNING_LEVEL1_IRQ >> 8;
|
||||
if (intRegister[0] & mask)
|
||||
return ((statusRegister[0] & mask) == mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AXP2101_isVbusRemoveIrq(void) {
|
||||
uint8_t mask = XPOWERS_AXP2101_VBUS_REMOVE_IRQ >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
return ((statusRegister[1] & mask) == mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AXP2101_isBatInsertIrq(void) {
|
||||
uint8_t mask = XPOWERS_AXP2101_BAT_INSERT_IRQ >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
return ((statusRegister[1] & mask) == mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AXP2101_isBatRemoveIrq(void) {
|
||||
uint8_t mask = XPOWERS_AXP2101_BAT_REMOVE_IRQ >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
return ((statusRegister[1] & mask) == mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AXP2101_isPekeyShortPressIrq(void) {
|
||||
uint8_t mask = XPOWERS_AXP2101_PKEY_SHORT_IRQ >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
return ((statusRegister[1] & mask) == mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AXP2101_isPekeyLongPressIrq(void) {
|
||||
uint8_t mask = XPOWERS_AXP2101_PKEY_LONG_IRQ >> 8;
|
||||
if (intRegister[1] & mask)
|
||||
return ((statusRegister[1] & mask) == mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AXP2101_isBatChargeDoneIrq(void) {
|
||||
uint8_t mask = XPOWERS_AXP2101_BAT_CHG_DONE_IRQ >> 8;
|
||||
if (intRegister[2] & mask)
|
||||
return ((statusRegister[2] & mask) == mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AXP2101_isBatChargeStartIrq(void) {
|
||||
uint8_t mask = XPOWERS_AXP2101_BAT_CHG_START_IRQ >> 8;
|
||||
if (intRegister[2] & mask)
|
||||
return ((statusRegister[2] & mask) == mask);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// value in mV
|
||||
uint32_t AXP2101_setSysPowerDownVoltage(uint16_t value) {
|
||||
uint8_t reg_value = 0;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
if (value % XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_STEPS) {
|
||||
//log_e("Mistake ! The steps is must %u mV", XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_STEPS);
|
||||
return 10;
|
||||
}
|
||||
if (value < XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_MIN) {
|
||||
//log_e("Mistake ! The minimum settable voltage of VSYS is %u mV", XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_MIN);
|
||||
return 10;
|
||||
} else if (value > XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_MAX) {
|
||||
//log_e("Mistake ! The maximum settable voltage of VSYS is %u mV", XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_MAX);
|
||||
return 10;
|
||||
}
|
||||
|
||||
status = HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_VOFF_SET, 1, ®_value, 1, 60);
|
||||
if (status != HAL_OK)
|
||||
return 1;
|
||||
|
||||
reg_value &= 0xF8;
|
||||
reg_value |= (uint8_t)((value - XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_MIN) / XPOWERS_AXP2101_VSYS_VOL_THRESHOLD_STEPS);
|
||||
return (uint32_t)HAL_I2C_Mem_Write(&hi2c2, 0x68, XPOWERS_AXP2101_VOFF_SET, 1, ®_value, 1, 60);
|
||||
}
|
||||
|
||||
uint32_t AXP2101_setChargingLedMode(uint8_t mode) {
|
||||
uint8_t reg_value = 0;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
switch (mode) {
|
||||
case XPOWERS_CHG_LED_OFF:
|
||||
// clrRegisterBit(XPOWERS_AXP2101_CHGLED_SET_CTRL, 0);
|
||||
// break;
|
||||
case XPOWERS_CHG_LED_BLINK_1HZ:
|
||||
case XPOWERS_CHG_LED_BLINK_4HZ:
|
||||
case XPOWERS_CHG_LED_ON:
|
||||
status = HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_CHGLED_SET_CTRL, 1, ®_value, 1, 60);
|
||||
if (status != HAL_OK)
|
||||
return 1;
|
||||
|
||||
reg_value &= 0xC8;
|
||||
reg_value |= 0x05; //use manual ctrl
|
||||
reg_value |= (mode << 4);
|
||||
|
||||
status = HAL_I2C_Mem_Write(&hi2c2, 0x68, XPOWERS_AXP2101_CHGLED_SET_CTRL, 1, ®_value, 1, 60);
|
||||
break;
|
||||
case XPOWERS_CHG_LED_CTRL_CHG:
|
||||
status = HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_CHGLED_SET_CTRL, 1, ®_value, 1, 60);
|
||||
if (status != HAL_OK)
|
||||
return 1;
|
||||
|
||||
reg_value &= 0xF9;
|
||||
reg_value |= 0x01; // use type A mode
|
||||
//reg_value |= 0x02; // use type B mode
|
||||
|
||||
status = HAL_I2C_Mem_Write(&hi2c2, 0x68, XPOWERS_AXP2101_CHGLED_SET_CTRL, 1, ®_value, 1, 60);
|
||||
break;
|
||||
default:
|
||||
status = 10;
|
||||
break;
|
||||
}
|
||||
|
||||
return (uint32_t)status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Low battery warning threshold 5-20%, 1% per step
|
||||
* @param percentage: 5 ~ 20
|
||||
* @retval Status code
|
||||
*/
|
||||
uint32_t AXP2101_setLowBatWarnThreshold(uint8_t percentage) {
|
||||
if (percentage < 5 || percentage > 20)
|
||||
return 1;
|
||||
|
||||
uint8_t reg_value = 0;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
status = HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_LOW_BAT_WARN_SET, 1, ®_value, 1, 60);
|
||||
if (status != HAL_OK)
|
||||
return 1;
|
||||
|
||||
reg_value &= 0x0F;
|
||||
reg_value |= (uint8_t)((percentage - 5) << 4);
|
||||
return HAL_I2C_Mem_Write(&hi2c2, 0x68, XPOWERS_AXP2101_LOW_BAT_WARN_SET, 1, ®_value, 1, 60);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Low battery shutdown threshold 0-15%, 1% per step
|
||||
* @param opt: 0 ~ 15
|
||||
* @retval Status code
|
||||
*/
|
||||
uint32_t AXP2101_setLowBatShutdownThreshold(uint8_t opt) {
|
||||
uint8_t reg_value = 0;
|
||||
HAL_StatusTypeDef status;
|
||||
|
||||
if (opt > 15)
|
||||
opt = 15;
|
||||
|
||||
status = HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_LOW_BAT_WARN_SET, 1, ®_value, 1, 60);
|
||||
if (status != HAL_OK)
|
||||
return 1;
|
||||
|
||||
reg_value &= 0xF0;
|
||||
reg_value |= opt;
|
||||
return HAL_I2C_Mem_Write(&hi2c2, 0x68, XPOWERS_AXP2101_LOW_BAT_WARN_SET, 1, ®_value, 1, 60);
|
||||
}
|
||||
|
||||
|
||||
uint8_t AXP2101_isBatteryConnect(void) {
|
||||
return getRegisterBit(XPOWERS_AXP2101_STATUS1, 3);
|
||||
}
|
||||
|
||||
uint8_t AXP2101_isCharging(void) {
|
||||
uint8_t reg_value = 0;
|
||||
|
||||
HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_STATUS2, 1, ®_value, 1, 60);
|
||||
|
||||
return (reg_value >> 5) == 0x01;
|
||||
}
|
||||
|
||||
uint32_t AXP2101_getIrqStatus(uint32_t* out_value) {
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
|
||||
status |= HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_INTSTS1, 1, &statusRegister[0], 1, 60);
|
||||
status |= HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_INTSTS2, 1, &statusRegister[1], 1, 60);
|
||||
status |= HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_INTSTS3, 1, &statusRegister[2], 1, 60);
|
||||
|
||||
((uint8_t*)&out_value)[0] = statusRegister[0];
|
||||
((uint8_t*)&out_value)[0] = statusRegister[1];
|
||||
((uint8_t*)&out_value)[0] = statusRegister[2];
|
||||
((uint8_t*)&out_value)[3] = 0xFF;
|
||||
|
||||
return (uint32_t)status;
|
||||
}
|
||||
|
||||
uint32_t AXP2101_getBatteryPercent(uint8_t* out_value) {
|
||||
if (!AXP2101_isBatteryConnect())
|
||||
return 1;
|
||||
|
||||
return HAL_I2C_Mem_Read(&hi2c2, 0x68, XPOWERS_AXP2101_BAT_PERCENT_DATA, 1, out_value, 1, 60);
|
||||
}
|
94
Core/Src/backlight.c
Normal file
94
Core/Src/backlight.c
Normal file
@ -0,0 +1,94 @@
|
||||
#include "backlight.h"
|
||||
#include "main.h"
|
||||
#include "regs.h"
|
||||
|
||||
|
||||
// LCD backlight curve based on brightness measurements for specific value of PWM duty cycle.
|
||||
// Using this, I've established a custom command curve.
|
||||
#define LCD_BCKL_STEPS 10
|
||||
//static const uint16_t lcd_bckl_steps[LCD_BCKL_STEPS] = {20, 60, 96, 134, 166, 192, 210, 256, 358, 460};
|
||||
static const uint16_t lcd_bckl_steps[LCD_BCKL_STEPS] = {10, 20, 40, 60, 80, 110, 150, 200, 256, 440};
|
||||
|
||||
#define KBD_BCKL_STEPS 4
|
||||
static const uint16_t kbd_bckl_steps[KBD_BCKL_STEPS] = {0, 40, 110, 260};
|
||||
|
||||
|
||||
inline void lcd_backlight_update_from_reg(void) {
|
||||
uint16_t val = 0;
|
||||
|
||||
val = lcd_bckl_steps[reg_get_value(REG_ID_BKL) % LCD_BCKL_STEPS];
|
||||
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, val);
|
||||
}
|
||||
|
||||
inline void lcd_backlight_on(void) {
|
||||
lcd_backlight_update_from_reg();
|
||||
}
|
||||
|
||||
inline void lcd_backlight_off(void) {
|
||||
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0x0000);
|
||||
}
|
||||
|
||||
inline void lcd_backlight_update(uint8_t step) {
|
||||
uint16_t val = 0;
|
||||
const uint8_t index = step % LCD_BCKL_STEPS;
|
||||
|
||||
val = lcd_bckl_steps[index];
|
||||
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, val);
|
||||
|
||||
reg_set_value(REG_ID_BKL, index);
|
||||
}
|
||||
|
||||
inline void lcd_backlight_update_up(void) {
|
||||
uint16_t val = 0;
|
||||
uint8_t index = reg_get_value(REG_ID_BKL) % LCD_BCKL_STEPS;
|
||||
|
||||
index = index < (LCD_BCKL_STEPS-1) ? index + 1 : (LCD_BCKL_STEPS-1);
|
||||
val = lcd_bckl_steps[index];
|
||||
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, val);
|
||||
|
||||
reg_set_value(REG_ID_BKL, index);
|
||||
}
|
||||
|
||||
inline void lcd_backlight_update_down(void) {
|
||||
uint16_t val = 0;
|
||||
uint8_t index = reg_get_value(REG_ID_BKL) % LCD_BCKL_STEPS;
|
||||
|
||||
index = index > 0 ? index - 1 : 0;
|
||||
val = lcd_bckl_steps[index];
|
||||
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, val);
|
||||
|
||||
reg_set_value(REG_ID_BKL, index);
|
||||
}
|
||||
|
||||
|
||||
inline void kbd_backlight_on(void) {
|
||||
uint16_t val = 0;
|
||||
|
||||
val = kbd_bckl_steps[reg_get_value(REG_ID_BK2) % KBD_BCKL_STEPS];
|
||||
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, val);
|
||||
}
|
||||
|
||||
inline void kbd_backlight_off(void) {
|
||||
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, 0x0000);
|
||||
}
|
||||
|
||||
inline void kbd_backlight_update(uint8_t step) {
|
||||
uint16_t val = 0;
|
||||
const uint8_t index = step % KBD_BCKL_STEPS;
|
||||
|
||||
val = kbd_bckl_steps[index];
|
||||
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, val);
|
||||
|
||||
reg_set_value(REG_ID_BK2, index);
|
||||
}
|
||||
|
||||
inline void kbd_backlight_update_loop(void) {
|
||||
uint16_t val = 0;
|
||||
uint8_t index = reg_get_value(REG_ID_BK2) % KBD_BCKL_STEPS;
|
||||
|
||||
index = index < (KBD_BCKL_STEPS-1) ? index + 1 : 0;
|
||||
val = kbd_bckl_steps[index];
|
||||
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, val);
|
||||
|
||||
reg_set_value(REG_ID_BK2, index);
|
||||
}
|
63
Core/Src/batt.c
Normal file
63
Core/Src/batt.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include "batt.h"
|
||||
#include "main.h"
|
||||
#include "axp2101.h"
|
||||
|
||||
|
||||
static uint32_t low_bat_count = 0;
|
||||
|
||||
void show_bat_segs(void) {
|
||||
if (AXP2101_isBatteryConnect() == 0)
|
||||
return;
|
||||
|
||||
uint8_t pcnt;
|
||||
if (AXP2101_getBatteryPercent(&pcnt) != HAL_OK)
|
||||
return;
|
||||
uint8_t prev_state = (LL_GPIO_IsOutputPinSet(SYS_LED_GPIO_Port, SYS_LED_Pin) == 0);
|
||||
uint8_t blink_cnt;
|
||||
|
||||
if(pcnt > 0 && pcnt < 33)
|
||||
blink_cnt = 1;
|
||||
else if(pcnt >= 33 && pcnt < 66)
|
||||
blink_cnt = 1;
|
||||
else if(pcnt >= 66 && pcnt <= 100)
|
||||
blink_cnt = 1;
|
||||
|
||||
flash_one_time(blink_cnt, prev_state);
|
||||
|
||||
if (AXP2101_isCharging())
|
||||
start_chg();
|
||||
}
|
||||
|
||||
// CAUTION: This is related to the battery charging and discharging logic. If you're not sure what you're doing, please don't modify it, as it could damage the battery.
|
||||
void low_bat(void) {
|
||||
uint8_t pcnt;
|
||||
if (AXP2101_getBatteryPercent(&pcnt) != HAL_OK)
|
||||
return;
|
||||
|
||||
if ((pcnt >= 0) && (pcnt <= (uint8_t)LOW_BAT_VAL)) {
|
||||
low_bat_count++;
|
||||
LL_GPIO_SetOutputPin(SYS_LED_GPIO_Port, SYS_LED_Pin);
|
||||
|
||||
if (pcnt <= 1) {
|
||||
AXP2101_setChargingLedMode(XPOWERS_CHG_LED_BLINK_4HZ);
|
||||
if(pcnt == 0 && low_bat_count >= 4)
|
||||
AXP2101_shutdown();
|
||||
} else {
|
||||
AXP2101_setChargingLedMode(XPOWERS_CHG_LED_ON);
|
||||
}
|
||||
} else {
|
||||
low_bat_count = 0;
|
||||
LL_GPIO_ResetOutputPin(SYS_LED_GPIO_Port, SYS_LED_Pin);
|
||||
AXP2101_setChargingLedMode(XPOWERS_CHG_LED_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
void start_chg(void) {
|
||||
LL_GPIO_ResetOutputPin(SYS_LED_GPIO_Port, SYS_LED_Pin);
|
||||
AXP2101_setChargingLedMode(XPOWERS_CHG_LED_BLINK_1HZ);
|
||||
}
|
||||
|
||||
void stop_chg(void) {
|
||||
AXP2101_setChargingLedMode(XPOWERS_CHG_LED_OFF);
|
||||
low_bat();
|
||||
}
|
427
Core/Src/eeprom.c
Normal file
427
Core/Src/eeprom.c
Normal file
@ -0,0 +1,427 @@
|
||||
//EEPROM emulation library for STM32F1XX with HAL-Driver
|
||||
//V2.0
|
||||
|
||||
|
||||
//includes
|
||||
#include "eeprom.h"
|
||||
|
||||
|
||||
//private function prototypes;
|
||||
static EEPROM_Result EEPROM_PageTransfer();
|
||||
static EEPROM_Result EEPROM_SetPageStatus(EEPROM_Page Page, EEPROM_PageStatus PageStatus);
|
||||
static EEPROM_Result EEPROM_PageToIndex(EEPROM_Page Page);
|
||||
|
||||
|
||||
//global variables
|
||||
static uint8_t EEPROM_SizeTable[EEPROM_VARIABLE_COUNT]; //EEPROM_SizeTable[i]: actual size of variable i (as EEPROM_Size)
|
||||
static uint16_t EEPROM_Index[EEPROM_VARIABLE_COUNT]; //EEPROM_Index[i]: actual address of variable i (physical address = EEPROM_START_ADDRESS + EEPROM_Index[i])
|
||||
//if EEPROM_Index[i] = 0 variable i not assigned
|
||||
|
||||
static uint32_t EEPROM_ValidPage = EEPROM_PAGE_NONE;
|
||||
static uint32_t EEPROM_ReceivingPage = EEPROM_PAGE_NONE;
|
||||
static uint32_t EEPROM_ErasedPage = EEPROM_PAGE_NONE;
|
||||
|
||||
static uint32_t EEPROM_NextIndex = 0;
|
||||
|
||||
|
||||
// initialize the EEPROM & restore the pages to a known good state in case of page's status corruption after a power loss
|
||||
// - unlock flash
|
||||
// - read each page status and check if valid
|
||||
// - if invalid page status, format EEPROM
|
||||
// - set global variables ValidPage, ReceivingPage and ErasedPage
|
||||
// - build address index
|
||||
// - resume page transfer if needed
|
||||
//
|
||||
// return: EEPROM_SUCCESS, EEPROM_NO_VALID_PAGE, EEPROM_FULL, EEPROM_ERROR, EEPROM_BUSY, EEPROM_TIMEOUT
|
||||
EEPROM_Result EEPROM_Init()
|
||||
{
|
||||
EEPROM_Result result;
|
||||
|
||||
//unlock the flash memory
|
||||
HAL_FLASH_Unlock();
|
||||
|
||||
//read each page status and check if valid
|
||||
EEPROM_PageStatus PageStatus0 = *((__IO uint16_t*) EEPROM_PAGE0);
|
||||
EEPROM_PageStatus PageStatus1 = *((__IO uint16_t*) EEPROM_PAGE1);
|
||||
uint8_t InvalidState = 0;
|
||||
if (PageStatus0 != EEPROM_VALID && PageStatus0 != EEPROM_RECEIVING && PageStatus0 != EEPROM_ERASED) InvalidState = 1;
|
||||
if (PageStatus1 != EEPROM_VALID && PageStatus1 != EEPROM_RECEIVING && PageStatus1 != EEPROM_ERASED) InvalidState = 1;
|
||||
if (PageStatus0 == PageStatus1) InvalidState = 1;
|
||||
|
||||
// if invalid page status, format EEPROM (erase both pages and set page0 as valid)
|
||||
if (InvalidState)
|
||||
{
|
||||
FLASH_EraseInitTypeDef EraseDefinitions;
|
||||
EraseDefinitions.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
EraseDefinitions.Banks = FLASH_BANK_1;
|
||||
EraseDefinitions.PageAddress = EEPROM_PAGE0;
|
||||
EraseDefinitions.NbPages = 2;
|
||||
uint32_t PageError;
|
||||
|
||||
result = HAL_FLASHEx_Erase(&EraseDefinitions, &PageError);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
|
||||
result = HAL_FLASH_Program(EEPROM_SIZE16, EEPROM_PAGE0, EEPROM_VALID);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
|
||||
PageStatus0 = EEPROM_VALID;
|
||||
PageStatus1 = EEPROM_ERASED;
|
||||
}
|
||||
|
||||
//set global variables ValidPage, ReceivingPage and ErasedPage (one stays EEPROM_PAGE_NONE)
|
||||
if (PageStatus0 == EEPROM_VALID) EEPROM_ValidPage = EEPROM_PAGE0;
|
||||
if (PageStatus1 == EEPROM_VALID) EEPROM_ValidPage = EEPROM_PAGE1;
|
||||
if (PageStatus0 == EEPROM_RECEIVING) EEPROM_ReceivingPage = EEPROM_PAGE0;
|
||||
if (PageStatus1 == EEPROM_RECEIVING) EEPROM_ReceivingPage = EEPROM_PAGE1;
|
||||
if (PageStatus0 == EEPROM_ERASED) EEPROM_ErasedPage = EEPROM_PAGE0;
|
||||
if (PageStatus1 == EEPROM_ERASED) EEPROM_ErasedPage = EEPROM_PAGE1;
|
||||
|
||||
//build address index (addresses from receiving page are dominant)
|
||||
EEPROM_PageToIndex(EEPROM_ValidPage);
|
||||
EEPROM_PageToIndex(EEPROM_ReceivingPage);
|
||||
|
||||
//if needed, resume page transfer or just mark receiving page as valid
|
||||
if (EEPROM_ReceivingPage != EEPROM_PAGE_NONE)
|
||||
{
|
||||
if (EEPROM_ValidPage == EEPROM_PAGE_NONE)
|
||||
{
|
||||
result = EEPROM_SetPageStatus(EEPROM_ReceivingPage, EEPROM_VALID);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = EEPROM_PageTransfer(EEPROM_ValidPage, EEPROM_ReceivingPage);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
}
|
||||
}
|
||||
|
||||
return EEPROM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// returns the last stored variable value which correspond to the passed variable name
|
||||
// - check if variable name exists
|
||||
// - check if variable was assigned
|
||||
// - read variable value from physical address with right size
|
||||
//
|
||||
// VariableName: name (number) of the variable to read
|
||||
// Value: outputs the variable value
|
||||
// return: EEPROM_SUCCESS, EEPROM_INVALID_NAME, EEPROM_NOT_ASSIGNED
|
||||
EEPROM_Result EEPROM_ReadVariable(uint16_t VariableName, EEPROM_Value* Value)
|
||||
{
|
||||
//check if variable name exists
|
||||
if (VariableName >= EEPROM_VARIABLE_COUNT) return EEPROM_INVALID_NAME;
|
||||
|
||||
//check if variable was assigned
|
||||
uint32_t Address = EEPROM_START_ADDRESS + EEPROM_Index[VariableName];
|
||||
if (Address == EEPROM_PAGE0) return EEPROM_NOT_ASSIGNED;
|
||||
|
||||
//read variable value from physical address with right size
|
||||
switch (EEPROM_SizeTable[VariableName])
|
||||
{
|
||||
case EEPROM_SIZE16: (*Value).uInt16 = *((__IO uint16_t*) Address); break;
|
||||
case EEPROM_SIZE32: (*Value).uInt32 = *((__IO uint32_t*) Address); break;
|
||||
case EEPROM_SIZE64: (*Value).uInt64 = *((__IO uint32_t*) Address) | ((uint64_t) *((__IO uint32_t*) (Address + 4)) << 32); break;
|
||||
default: return EEPROM_NOT_ASSIGNED;
|
||||
}
|
||||
|
||||
return EEPROM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// writes variable in EEPROM if page not full
|
||||
// - get writing page's end address
|
||||
// - calculate memory usage of variable
|
||||
// - check if page full
|
||||
// - check if data is too much to store on one page
|
||||
// - mark the target page as receiving
|
||||
// - change next index to receiving page
|
||||
// - write the variable to target page
|
||||
// - do page transfer
|
||||
// - else (if enough space)
|
||||
// - write variable value
|
||||
// - create and write variable header (size and name)
|
||||
// - update index & size table
|
||||
// - update next index
|
||||
//
|
||||
// VariableName: name (number) of the variable to write
|
||||
// Value: value to be written
|
||||
// Size: size of "Value" as EEPROM_Size
|
||||
// return: EEPROM_SUCCESS, EEPROM_NO_VALID_PAGE, EEPROM_FULL, EEPROM_ERROR, EEPROM_BUSY, EEPROM_TIMEOUT
|
||||
EEPROM_Result EEPROM_WriteVariable(uint16_t VariableName, EEPROM_Value Value, uint8_t Size)
|
||||
{
|
||||
EEPROM_Result result;
|
||||
|
||||
//get writing page's end address (prefer writing to receiving page)
|
||||
EEPROM_Page WritingPage = EEPROM_ValidPage;
|
||||
if (EEPROM_ReceivingPage != EEPROM_PAGE_NONE) WritingPage = EEPROM_ReceivingPage;
|
||||
if (WritingPage == EEPROM_PAGE_NONE) return EEPROM_NO_VALID_PAGE;
|
||||
uint32_t PageEndAddress = WritingPage + FLASH_PAGE_SIZE;
|
||||
|
||||
//calculate memory usage of variable
|
||||
uint8_t Bytes = 2 + (1 << Size);
|
||||
if (Size == EEPROM_SIZE_DELETED) Bytes = 2;
|
||||
|
||||
//check if enough free space or page full
|
||||
if (EEPROM_NextIndex == 0 || PageEndAddress - EEPROM_NextIndex < Bytes)
|
||||
{
|
||||
//check if data is too much to store on one page
|
||||
uint16_t RequiredMemory = 2;
|
||||
for (uint16_t i = 0; i < EEPROM_VARIABLE_COUNT; i++)
|
||||
{
|
||||
if (i == VariableName) RequiredMemory += 2 + (1 << Size);
|
||||
else if (EEPROM_SizeTable[i] != EEPROM_SIZE_DELETED) RequiredMemory += 2 + (1 << EEPROM_SizeTable[i]);
|
||||
}
|
||||
if (RequiredMemory > FLASH_PAGE_SIZE) return EEPROM_FULL;
|
||||
|
||||
//mark the empty page as receiving
|
||||
result = EEPROM_SetPageStatus(EEPROM_ErasedPage, EEPROM_RECEIVING);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
|
||||
//change next index to receiving page
|
||||
EEPROM_NextIndex = EEPROM_ReceivingPage + 2;
|
||||
|
||||
//write the variable to receiving page (by calling this function again)
|
||||
result = EEPROM_WriteVariable(VariableName, Value, Size);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
|
||||
//do page transfer
|
||||
result = EEPROM_PageTransfer();
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
}
|
||||
|
||||
//else (if enough space)
|
||||
else
|
||||
{
|
||||
//write variable value
|
||||
if (Size != EEPROM_SIZE_DELETED)
|
||||
{
|
||||
result = HAL_FLASH_Program(Size, EEPROM_NextIndex + 2, Value.uInt64);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
}
|
||||
|
||||
//create and write variable header (size and name)
|
||||
uint16_t VariableHeader = VariableName + (Size << 14);
|
||||
result = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, EEPROM_NextIndex, VariableHeader);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
|
||||
//update index & size table
|
||||
EEPROM_Index[VariableName] = EEPROM_NextIndex + 2 - EEPROM_START_ADDRESS;
|
||||
EEPROM_SizeTable[VariableName] = Size;
|
||||
if (Size == EEPROM_SIZE_DELETED) EEPROM_Index[VariableName] = 0;
|
||||
|
||||
//update next index
|
||||
EEPROM_NextIndex += Bytes;
|
||||
if (EEPROM_NextIndex >= PageEndAddress) EEPROM_NextIndex = 0;
|
||||
}
|
||||
|
||||
return EEPROM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
//marks a variable as deleted so it can't be read anymore and is discarded on next page transfer
|
||||
// - call write variable with size EEPROM_SIZE_DELETED
|
||||
//
|
||||
// VariableName: name (number) of the variable to delete
|
||||
// return: EEPROM_SUCCESS, EEPROM_NO_VALID_PAGE, EEPROM_FULL, EEPROM_ERROR, EEPROM_BUSY, EEPROM_TIMEOUT
|
||||
EEPROM_Result EEPROM_DeleteVariable(uint16_t VariableName)
|
||||
{
|
||||
return EEPROM_WriteVariable(VariableName, (EEPROM_Value) (uint16_t) 0, EEPROM_SIZE_DELETED);
|
||||
}
|
||||
|
||||
|
||||
// transfers latest variable values from valid page to receiving page
|
||||
// - get start & end address of valid page (source)
|
||||
// - copy each variable
|
||||
// - check if is stored on the source page
|
||||
// - read variable value
|
||||
// - write variable to receiving page
|
||||
// - erase source page
|
||||
// - mark receiving page as valid
|
||||
//
|
||||
// return: EEPROM_SUCCESS, EEPROM_NO_VALID_PAGE, EEPROM_FULL, EEPROM_ERROR, EEPROM_BUSY, EEPROM_TIMEOUT
|
||||
static EEPROM_Result EEPROM_PageTransfer()
|
||||
{
|
||||
EEPROM_Result result;
|
||||
EEPROM_Value Value;
|
||||
|
||||
//get start & end address of valid page (source) (as offset to EEPROM start)
|
||||
uint16_t StartAddress = EEPROM_ValidPage - EEPROM_START_ADDRESS;
|
||||
uint16_t EndAddress = EEPROM_ValidPage - EEPROM_START_ADDRESS + FLASH_PAGE_SIZE;
|
||||
|
||||
//copy each variable
|
||||
for (uint16_t i = 0; i < EEPROM_VARIABLE_COUNT; i++)
|
||||
{
|
||||
//check if is stored on the source page
|
||||
if (StartAddress < EEPROM_Index[i] && EEPROM_Index[i] < EndAddress)
|
||||
{
|
||||
//read variable value (if possible)
|
||||
if (EEPROM_ReadVariable(i, &Value) == EEPROM_SUCCESS)
|
||||
{
|
||||
//write variable to receiving page
|
||||
result = EEPROM_WriteVariable(i, Value, EEPROM_SizeTable[i]);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//erase source page
|
||||
result = EEPROM_SetPageStatus(EEPROM_ValidPage, EEPROM_ERASED);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
|
||||
//mark receiving page as valid
|
||||
result = EEPROM_SetPageStatus(EEPROM_ReceivingPage, EEPROM_VALID);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
|
||||
return EEPROM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// sets the page status and updates references from global variables
|
||||
// - check if erase operation required
|
||||
// - remove every variable from index, that is stored on erase page
|
||||
// - setup erase definitions
|
||||
// - erase page
|
||||
// - else write status to flash
|
||||
// - update global page status variables
|
||||
//
|
||||
// Page: page to change the status (as EEPROM_Page)
|
||||
// PageStatus: page status to set for page (as EEPROM_PageStatus)
|
||||
// return: EEPROM_SUCCESS, EEPROM_ERROR, EEPROM_BUSY or EEPROM_TIMEOUT
|
||||
static EEPROM_Result EEPROM_SetPageStatus(EEPROM_Page Page, EEPROM_PageStatus PageStatus)
|
||||
{
|
||||
EEPROM_Result result;
|
||||
|
||||
//check if erase operation required
|
||||
if (PageStatus == EEPROM_ERASED)
|
||||
{
|
||||
//remove every variable from index, that is stored on erase page
|
||||
uint16_t StartAddress = Page - EEPROM_START_ADDRESS;
|
||||
uint16_t EndAddress = Page - EEPROM_START_ADDRESS + FLASH_PAGE_SIZE;
|
||||
for (uint16_t i = 0; i < EEPROM_VARIABLE_COUNT; i++)
|
||||
{
|
||||
if (StartAddress < EEPROM_Index[i] && EEPROM_Index[i] < EndAddress) EEPROM_Index[i] = 0;
|
||||
}
|
||||
|
||||
//setup erase definitions
|
||||
FLASH_EraseInitTypeDef EraseDefinitions;
|
||||
EraseDefinitions.TypeErase = FLASH_TYPEERASE_PAGES;
|
||||
EraseDefinitions.Banks = FLASH_BANK_1;
|
||||
EraseDefinitions.PageAddress = Page;
|
||||
EraseDefinitions.NbPages = 1;
|
||||
uint32_t PageError;
|
||||
|
||||
//erase page
|
||||
result = HAL_FLASHEx_Erase(&EraseDefinitions, &PageError);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
}
|
||||
|
||||
//else write status to flash
|
||||
else
|
||||
{
|
||||
result = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Page, PageStatus);
|
||||
if (result != EEPROM_SUCCESS) return result;
|
||||
}
|
||||
|
||||
//update global page status variables (remove page from old status and attach to new status)
|
||||
if (EEPROM_ValidPage == Page) EEPROM_ValidPage = EEPROM_PAGE_NONE;
|
||||
else if (EEPROM_ReceivingPage == Page) EEPROM_ReceivingPage = EEPROM_PAGE_NONE;
|
||||
else if (EEPROM_ErasedPage == Page) EEPROM_ErasedPage = EEPROM_PAGE_NONE;
|
||||
|
||||
if (PageStatus == EEPROM_VALID) EEPROM_ValidPage = Page;
|
||||
else if (PageStatus == EEPROM_RECEIVING) EEPROM_ReceivingPage = Page;
|
||||
else if (PageStatus == EEPROM_ERASED) EEPROM_ErasedPage = Page;
|
||||
|
||||
return EEPROM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// reads the whole page, fills the index with variable addresses and the size table with variable sizes
|
||||
// - declare variables
|
||||
// - ignore call when Page is PAGE_NONE
|
||||
// - get page addresses
|
||||
// - loop through page addresses
|
||||
// - read potential variable header
|
||||
// - if no header written
|
||||
// - loop through next 4 halfword and check if there is anything written
|
||||
// - while looping count the size of written data
|
||||
// - if no data found, last variable of page was reached (return)
|
||||
// - else (if header written)
|
||||
// - get size code
|
||||
// - check for valid name
|
||||
// - if everything valid, update the index and the size table
|
||||
// - calculate size in bytes from size code
|
||||
// - go to next address on page
|
||||
// - set next free flash address
|
||||
// - return on loop end
|
||||
//
|
||||
// Page: page to search for variables
|
||||
// return: EEPROM_SUCCESS
|
||||
static EEPROM_Result EEPROM_PageToIndex(EEPROM_Page Page)
|
||||
{
|
||||
//declare variables
|
||||
uint16_t VariableHeader; //header of current variable (first 2 bits size code, rest name)
|
||||
uint8_t SizeCode; //size of current variable as Size code
|
||||
uint8_t Size; //size of current variable in bytes
|
||||
uint16_t Name; //name of current variable
|
||||
|
||||
//ignore call when Page is PAGE_NONE
|
||||
if (Page == EEPROM_PAGE_NONE) return EEPROM_SUCCESS;
|
||||
|
||||
//get page addresses
|
||||
uint32_t Address = Page + 2;
|
||||
uint32_t PageEndAddress = Page + FLASH_PAGE_SIZE;
|
||||
|
||||
//loop through page starting after page header
|
||||
while (Address < PageEndAddress)
|
||||
{
|
||||
//read potential variable header
|
||||
VariableHeader = *((__IO uint16_t*) Address);
|
||||
|
||||
//if no header written (causes: end of data reached or reset while writing)
|
||||
if (VariableHeader == 0xFFFF)
|
||||
{
|
||||
//loop through next 4 halfword and check if there is anything written
|
||||
Size = 0;
|
||||
for (uint8_t i = 2; i <= 8; i += 2)
|
||||
{
|
||||
if (Address + i >= PageEndAddress) break;
|
||||
//while looping count the size of written data (resulting from reset while writing)
|
||||
if (*((__IO uint16_t*) (Address + i)) != 0xFFFF) Size = i;
|
||||
}
|
||||
//if no data found, last variable of page was reached (end loop)
|
||||
if (Size == 0) break;
|
||||
}
|
||||
|
||||
//else (if header written, proper variable value is following)
|
||||
else
|
||||
{
|
||||
//get size code
|
||||
SizeCode = VariableHeader >> 14;
|
||||
|
||||
//check for valid name (VARIABLE_COUNT might have been reduced between builds, but old variables are still in flash)
|
||||
Name = VariableHeader & 0b0011111111111111;
|
||||
if (Name < EEPROM_VARIABLE_COUNT)
|
||||
{
|
||||
//if everything valid, update the index and the size table
|
||||
EEPROM_Index[Name] = Address + 2 - EEPROM_START_ADDRESS;
|
||||
EEPROM_SizeTable[Name] = SizeCode;
|
||||
if (SizeCode == EEPROM_SIZE_DELETED) EEPROM_Index[Name] = 0;
|
||||
}
|
||||
|
||||
//calculate size in bytes from size code
|
||||
Size = 1 << SizeCode;
|
||||
if (SizeCode == EEPROM_SIZE_DELETED) Size = 0;
|
||||
}
|
||||
|
||||
//go to next address on page
|
||||
Address = Address + 2 + Size;
|
||||
}
|
||||
|
||||
//set next free flash address
|
||||
EEPROM_NextIndex = Address;
|
||||
if (Address >= PageEndAddress) EEPROM_NextIndex = 0;
|
||||
|
||||
//return on loop end
|
||||
return EEPROM_SUCCESS;
|
||||
}
|
59
Core/Src/fifo.c
Normal file
59
Core/Src/fifo.c
Normal file
@ -0,0 +1,59 @@
|
||||
#include "fifo.h"
|
||||
|
||||
|
||||
static struct fifo_item fifo[FIFO_SIZE] = {0};
|
||||
static uint8_t count = 0;
|
||||
static volatile uint8_t read_idx = 0;
|
||||
static volatile uint8_t write_idx = 0;
|
||||
|
||||
|
||||
inline uint8_t fifo_count(void) {
|
||||
return count;
|
||||
}
|
||||
|
||||
void fifo_flush(void) {
|
||||
write_idx = 0;
|
||||
read_idx = 0;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
uint8_t fifo_enqueue(const struct fifo_item item) {
|
||||
if (count >= FIFO_SIZE)
|
||||
return 0;
|
||||
|
||||
fifo[write_idx].state = item.state;
|
||||
fifo[write_idx].key = item.key;
|
||||
|
||||
write_idx++;
|
||||
write_idx %= FIFO_SIZE;
|
||||
++count;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void fifo_enqueue_force(const struct fifo_item item) {
|
||||
if (fifo_enqueue(item))
|
||||
return;
|
||||
|
||||
fifo[write_idx].state = item.state;
|
||||
fifo[write_idx].key = item.key;
|
||||
write_idx++;
|
||||
write_idx %= FIFO_SIZE;
|
||||
|
||||
read_idx++;
|
||||
read_idx %= FIFO_SIZE;
|
||||
}
|
||||
|
||||
void fifo_dequeue(struct fifo_item* const outItem) {
|
||||
if (outItem == NULL)
|
||||
return;
|
||||
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
outItem->state = fifo[read_idx].state;
|
||||
outItem->key = fifo[read_idx].key;
|
||||
read_idx++;
|
||||
read_idx %= FIFO_SIZE;
|
||||
--count;
|
||||
}
|
408
Core/Src/keyboard.c
Normal file
408
Core/Src/keyboard.c
Normal file
@ -0,0 +1,408 @@
|
||||
#include "keyboard.h"
|
||||
#include "regs.h"
|
||||
#include "backlight.h"
|
||||
#include "batt.h"
|
||||
|
||||
|
||||
enum mod {
|
||||
MOD_NONE = 0,
|
||||
MOD_SYM,
|
||||
MOD_ALT,
|
||||
MOD_SHL,
|
||||
MOD_SHR,
|
||||
MOD_CTRL,
|
||||
MOD_LAST,
|
||||
};
|
||||
|
||||
struct entry {
|
||||
uint8_t chr;
|
||||
uint8_t symb;
|
||||
enum mod mod;
|
||||
};
|
||||
#define INIT_ENTRY1(a) {a,a,MOD_NONE}
|
||||
#define INIT_ENTRY2(a,b) {a,b,MOD_NONE}
|
||||
|
||||
struct list_item {
|
||||
const struct entry *p_entry;
|
||||
uint32_t hold_start_time;
|
||||
uint32_t last_repeat_time;
|
||||
enum key_state state;
|
||||
uint8_t mods[MOD_LAST];
|
||||
};
|
||||
|
||||
struct gpio_pin {
|
||||
GPIO_TypeDef *GPIOx;
|
||||
uint32_t PinMask;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static const struct entry kbd_entries[][NUM_OF_COLS] = {
|
||||
{INIT_ENTRY2(KEY_F5,KEY_F10), INIT_ENTRY2(KEY_F4,KEY_F9), INIT_ENTRY2(KEY_F3,KEY_F8),INIT_ENTRY2(KEY_F2,KEY_F7), INIT_ENTRY2(KEY_F1,KEY_F6), INIT_ENTRY2('`','~'),INIT_ENTRY2('3','#'), INIT_ENTRY2('2','@')},
|
||||
{INIT_ENTRY1(KEY_BACKSPACE), INIT_ENTRY2(KEY_DEL,KEY_END),INIT_ENTRY1(KEY_CAPS_LOCK),INIT_ENTRY2(KEY_TAB,KEY_HOME),INIT_ENTRY2(KEY_ESC,KEY_BREAK),INIT_ENTRY2('4','$'),INIT_ENTRY1('E'), INIT_ENTRY1('W')},
|
||||
{INIT_ENTRY1('P'), INIT_ENTRY2('=','+'), INIT_ENTRY2('-','_'), INIT_ENTRY2('\\','|'), INIT_ENTRY2('/','?'), INIT_ENTRY1('R'), INIT_ENTRY1('S'), INIT_ENTRY2('1','!')},
|
||||
{INIT_ENTRY2(KEY_ENTER,KEY_INSERT), INIT_ENTRY2('8','*'), INIT_ENTRY2('7','&'), INIT_ENTRY2('6','^'), INIT_ENTRY2('5','%'), INIT_ENTRY1('F'), INIT_ENTRY1('X'), INIT_ENTRY1('Q')},
|
||||
{INIT_ENTRY2('.','>'), INIT_ENTRY1('I'), INIT_ENTRY1('U'), INIT_ENTRY1('Y'), INIT_ENTRY1('T'), INIT_ENTRY1('V'), INIT_ENTRY2(';',':'), INIT_ENTRY1('A')},
|
||||
{INIT_ENTRY1('L'), INIT_ENTRY1('K'), INIT_ENTRY1('J'), INIT_ENTRY1('H'), INIT_ENTRY1('G'), INIT_ENTRY1('C'), INIT_ENTRY2('\'','"'),INIT_ENTRY1('Z')},
|
||||
{INIT_ENTRY1('O'), INIT_ENTRY2(',','<'), INIT_ENTRY1('M'), INIT_ENTRY1('N'), INIT_ENTRY1('B'), INIT_ENTRY1('D'), INIT_ENTRY1(' '), INIT_ENTRY1(0x00)}
|
||||
};
|
||||
|
||||
static const struct entry btn_entries[12] = {
|
||||
{.mod = MOD_ALT},
|
||||
{.mod = MOD_CTRL},
|
||||
{.mod = MOD_SHL},
|
||||
{.mod = MOD_SHR},
|
||||
INIT_ENTRY2('0',')'),
|
||||
INIT_ENTRY2('9','('),
|
||||
INIT_ENTRY2(']','}'),
|
||||
INIT_ENTRY2('[','{'),
|
||||
INIT_ENTRY1(KEY_RIGHT),
|
||||
INIT_ENTRY2(KEY_UP,KEY_PAGE_UP),
|
||||
INIT_ENTRY2(KEY_DOWN,KEY_PAGE_DOWN),
|
||||
INIT_ENTRY1(KEY_LEFT)
|
||||
};
|
||||
|
||||
static const struct gpio_pin row_pins[NUM_OF_ROWS] = {
|
||||
{ROW_1_GPIO_Port, ROW_1_Pin},
|
||||
{ROW_2_GPIO_Port, ROW_2_Pin},
|
||||
{ROW_3_GPIO_Port, ROW_3_Pin},
|
||||
{ROW_4_GPIO_Port, ROW_4_Pin},
|
||||
{ROW_5_GPIO_Port, ROW_5_Pin},
|
||||
{ROW_6_GPIO_Port, ROW_6_Pin},
|
||||
{ROW_7_GPIO_Port, ROW_7_Pin}
|
||||
};
|
||||
|
||||
static const struct gpio_pin col_pins[NUM_OF_COLS] = {
|
||||
{COL_1_GPIO_Port, COL_1_Pin},
|
||||
{COL_2_GPIO_Port, COL_2_Pin},
|
||||
{COL_3_GPIO_Port, COL_3_Pin},
|
||||
{COL_4_GPIO_Port, COL_4_Pin},
|
||||
{COL_5_GPIO_Port, COL_5_Pin},
|
||||
{COL_6_GPIO_Port, COL_6_Pin},
|
||||
{COL_7_GPIO_Port, COL_7_Pin},
|
||||
{COL_8_GPIO_Port, COL_8_Pin}
|
||||
};
|
||||
|
||||
static const struct gpio_pin btn_pins[12] = {
|
||||
{KEY_1_GPIO_Port, KEY_1_Pin},
|
||||
{KEY_2_GPIO_Port, KEY_2_Pin},
|
||||
{KEY_3_GPIO_Port, KEY_3_Pin},
|
||||
{KEY_4_GPIO_Port, KEY_4_Pin},
|
||||
{KEY_5_GPIO_Port, KEY_5_Pin},
|
||||
{KEY_6_GPIO_Port, KEY_6_Pin},
|
||||
{KEY_7_GPIO_Port, KEY_7_Pin},
|
||||
{KEY_8_GPIO_Port, KEY_8_Pin},
|
||||
{KEY_9_GPIO_Port, KEY_9_Pin},
|
||||
{KEY_10_GPIO_Port, KEY_10_Pin},
|
||||
{KEY_11_GPIO_Port, KEY_11_Pin},
|
||||
{KEY_12_GPIO_Port, KEY_12_Pin}
|
||||
};
|
||||
|
||||
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 uint8_t mods[MOD_LAST];
|
||||
static uint8_t capslock_changed = 0;
|
||||
static uint8_t capslock = 0;
|
||||
static uint8_t numlock_changed = 0;
|
||||
static uint8_t numlock = 0;
|
||||
|
||||
|
||||
inline void keyboard_set_key_callback(key_callback callback) {
|
||||
_key_callback = callback;
|
||||
}
|
||||
|
||||
inline void keyboard_set_lock_callback(lock_callback callback) {
|
||||
_lock_callback = callback;
|
||||
}
|
||||
|
||||
inline uint8_t keyboard_get_capslock(void) {
|
||||
return capslock & 0x1;
|
||||
}
|
||||
|
||||
inline uint8_t keyboard_get_numlock(void) {
|
||||
return numlock & 0x1;
|
||||
}
|
||||
|
||||
static void transition_to(struct list_item * const p_item, const enum key_state next_state) {
|
||||
uint8_t output = 1;
|
||||
const struct entry * const p_entry = p_item->p_entry;
|
||||
|
||||
p_item->state = next_state;
|
||||
|
||||
if (!_key_callback || !p_entry)
|
||||
return;
|
||||
|
||||
char chr = p_entry->chr;
|
||||
|
||||
switch (p_entry->mod) {
|
||||
case MOD_ALT:
|
||||
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
||||
chr = KEY_MOD_ALT;
|
||||
break;
|
||||
|
||||
case MOD_SHL:
|
||||
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
||||
chr = KEY_MOD_SHL;
|
||||
break;
|
||||
|
||||
case MOD_SHR:
|
||||
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
||||
chr = KEY_MOD_SHR;
|
||||
break;
|
||||
|
||||
case MOD_SYM:
|
||||
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
||||
chr = KEY_MOD_SYM;
|
||||
break;
|
||||
|
||||
case MOD_CTRL:
|
||||
if (reg_is_bit_set(REG_ID_CFG, CFG_REPORT_MODS))
|
||||
chr = KEY_MOD_CTRL;
|
||||
break;
|
||||
|
||||
default: //toggle operation
|
||||
if (chr == KEY_CAPS_LOCK && next_state == KEY_STATE_PRESSED) {
|
||||
capslock = (capslock & 0x1) ^ 0x1;
|
||||
capslock_changed = 1;
|
||||
}
|
||||
|
||||
if (reg_is_bit_set(REG_ID_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];
|
||||
|
||||
if (shift && (chr <'A' || chr >'Z')) {
|
||||
chr = p_entry->symb;
|
||||
} else if (capslock && (chr >= 'A' && chr <= 'Z')) {
|
||||
//pass
|
||||
} else if (alt) {
|
||||
//ctrl for operators
|
||||
if (next_state == KEY_STATE_PRESSED) {
|
||||
if (chr == ',' || chr == '.' || chr == ' ' || chr == 'B') {
|
||||
output = 0;
|
||||
} else if (chr == 'I') {
|
||||
output = 1;
|
||||
chr = KEY_INSERT;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_state == KEY_STATE_RELEASED) {
|
||||
if (chr == ',' || chr == '.' || chr == ' ' || chr == 'B') {
|
||||
output = 0;
|
||||
} else if(chr == 'I'){
|
||||
output = 1;
|
||||
chr = KEY_INSERT;
|
||||
}
|
||||
}
|
||||
|
||||
if(next_state == KEY_STATE_RELEASED) {
|
||||
if(chr ==',')
|
||||
lcd_backlight_update_down();
|
||||
else if(chr =='.')
|
||||
lcd_backlight_update_up();
|
||||
else if(chr == ' ')
|
||||
//loop update keyboard backlight
|
||||
kbd_backlight_update_loop();
|
||||
else if(chr == 'B')
|
||||
show_bat_segs();
|
||||
}
|
||||
} else if (!shift && (chr >= 'A' && chr <= 'Z')) {
|
||||
chr = (chr + ' '); // uppercase to lowercase for a to z
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (chr != 0 && output == 1) {
|
||||
if(next_state == KEY_STATE_HOLD &&
|
||||
((chr >= 32 && chr <= 127) || chr == KEY_ENTER || chr == KEY_TAB || chr == KEY_DEL || chr == KEY_BACKSPACE || chr == KEY_UP || chr == KEY_DOWN || chr == KEY_RIGHT || chr == KEY_LEFT) )
|
||||
_key_callback(chr, KEY_STATE_PRESSED);
|
||||
else
|
||||
_key_callback(chr, next_state);
|
||||
}
|
||||
}
|
||||
|
||||
static void next_item_state(struct list_item* const p_item, const uint8_t pressed) {
|
||||
switch (p_item->state) {
|
||||
default:
|
||||
case KEY_STATE_IDLE:
|
||||
if (pressed) {
|
||||
if (p_item->p_entry->mod != MOD_NONE)
|
||||
mods[p_item->p_entry->mod] = 1;
|
||||
|
||||
if (!capslock_changed && mods[MOD_SHR] && mods[MOD_ALT]) {
|
||||
capslock = 1;
|
||||
capslock_changed = 1;
|
||||
}
|
||||
|
||||
if (!numlock_changed && mods[MOD_SHL] && mods[MOD_ALT]) {
|
||||
numlock = 1;
|
||||
numlock_changed = 1;
|
||||
}
|
||||
|
||||
if (!capslock_changed && (mods[MOD_SHL] || mods[MOD_SHR])) {
|
||||
capslock = 0;
|
||||
capslock_changed = 1;
|
||||
}
|
||||
|
||||
if (!numlock_changed && (mods[MOD_SHL] || mods[MOD_SHR])) {
|
||||
numlock = 0;
|
||||
numlock_changed = 1;
|
||||
}
|
||||
|
||||
if (!mods[MOD_ALT]) {
|
||||
capslock_changed = 0;
|
||||
numlock_changed = 0;
|
||||
}
|
||||
|
||||
if (_lock_callback && (capslock_changed || numlock_changed))
|
||||
_lock_callback(capslock_changed, numlock_changed);
|
||||
|
||||
transition_to(p_item, KEY_STATE_PRESSED);
|
||||
|
||||
p_item->hold_start_time = uptime_ms();
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_STATE_PRESSED:
|
||||
if (uptime_ms() > p_item->hold_start_time + KEY_HOLD_TIME) {
|
||||
transition_to(p_item, KEY_STATE_HOLD);
|
||||
p_item->last_repeat_time = uptime_ms();
|
||||
} else if (!pressed)
|
||||
transition_to(p_item, KEY_STATE_RELEASED);
|
||||
break;
|
||||
|
||||
case KEY_STATE_HOLD:
|
||||
if (!pressed)
|
||||
transition_to(p_item, KEY_STATE_RELEASED);
|
||||
else {
|
||||
if (uptime_ms() > p_item->hold_start_time + KEY_HOLD_TIME) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_STATE_RELEASED:
|
||||
if (p_item->p_entry->mod != MOD_NONE)
|
||||
mods[p_item->p_entry->mod] = 0;
|
||||
|
||||
p_item->p_entry = NULL;
|
||||
transition_to(p_item, KEY_STATE_IDLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void keyboard_process(void) {
|
||||
js_bits = 0xFF;
|
||||
|
||||
if (uptime_ms() <= (last_process_time + KEY_POLL_TIME))
|
||||
return;
|
||||
|
||||
// Scan for columns
|
||||
for (uint8_t c = 0; c < NUM_OF_COLS; ++c) {
|
||||
uint8_t col_value = 0;
|
||||
// Enable the columns signal - OD logic
|
||||
LL_GPIO_ResetOutputPin(col_pins[c].GPIOx, col_pins[c].PinMask);
|
||||
|
||||
// Scan for rows
|
||||
for (uint8_t r = 0; r < NUM_OF_ROWS; ++r) {
|
||||
const uint8_t pressed = (LL_GPIO_IsInputPinSet(row_pins[r].GPIOx, row_pins[r].PinMask) == 0);
|
||||
uint8_t row_bit = (1 << r);
|
||||
|
||||
if (pressed) {
|
||||
if (c == 1 && r == 4)
|
||||
js_bits &= ~row_bit;
|
||||
col_value &= ~row_bit;
|
||||
} else {
|
||||
if (c == 1 && r == 4) {
|
||||
js_bits |= row_bit;
|
||||
}
|
||||
col_value |= row_bit;
|
||||
}
|
||||
|
||||
const int32_t key_idx = (int32_t)((r * NUM_OF_COLS) + c);
|
||||
int32_t list_idx = -1;
|
||||
for (int32_t i = 0; i < KEY_LIST_SIZE; ++i) {
|
||||
if (keys_list[i].p_entry != &((const struct entry*)kbd_entries)[key_idx])
|
||||
continue;
|
||||
|
||||
list_idx = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (list_idx > -1) {
|
||||
next_item_state(&keys_list[list_idx], pressed);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pressed)
|
||||
continue;
|
||||
|
||||
for (uint32_t i = 0; i < KEY_LIST_SIZE; ++i) {
|
||||
if (keys_list[i].p_entry != NULL)
|
||||
continue;
|
||||
|
||||
keys_list[i].p_entry = &((const struct entry*)kbd_entries)[key_idx];
|
||||
keys_list[i].state = KEY_STATE_IDLE;
|
||||
next_item_state(&keys_list[i], pressed);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Disable the columns signal - OD logic
|
||||
LL_GPIO_SetOutputPin(col_pins[c].GPIOx, col_pins[c].PinMask);
|
||||
|
||||
io_matrix[c] = col_value;
|
||||
for (uint8_t b = 0; b < 12; ++b) {
|
||||
const uint8_t pressed = (LL_GPIO_IsInputPinSet(btn_pins[b].GPIOx, btn_pins[b].PinMask) == 0);
|
||||
if (b < 8) { // read BTN1->BTN8
|
||||
if (pressed)
|
||||
io_matrix[b] &= (uint8_t)(~(1 << 7));
|
||||
else
|
||||
io_matrix[b] |= (1 << 7);
|
||||
} else { //c64 joystick arrow keys
|
||||
//B12=left,, B11=down,B10 = up,B9 = right
|
||||
if (pressed)
|
||||
js_bits &= (uint8_t)(~(1 << (b - 8)));
|
||||
else
|
||||
js_bits |= (1 << (b - 8));
|
||||
}
|
||||
|
||||
int8_t list_idx = -1;
|
||||
for (int8_t i = 0; i < KEY_LIST_SIZE; ++i) {
|
||||
if (keys_list[i].p_entry != &((const struct entry*)btn_entries)[b])
|
||||
continue;
|
||||
|
||||
list_idx = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (list_idx > -1) {
|
||||
next_item_state(&keys_list[list_idx], pressed);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pressed)
|
||||
continue;
|
||||
|
||||
for (uint8_t i = 0 ; i < KEY_LIST_SIZE; ++i) {
|
||||
if (keys_list[i].p_entry != NULL)
|
||||
continue;
|
||||
|
||||
keys_list[i].p_entry = &((const struct entry*)btn_entries)[b];
|
||||
keys_list[i].state = KEY_STATE_IDLE;
|
||||
next_item_state(&keys_list[i], pressed);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
io_matrix[8] = 0xFF;
|
||||
last_process_time = uptime_ms();
|
||||
}
|
||||
}
|
654
Core/Src/main.c
654
Core/Src/main.c
@ -1,19 +1,17 @@
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file : main.c
|
||||
* @brief : Main program body
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2025 STMicroelectronics.
|
||||
* Copyright (c) 2025 C.ARE (JackCarterSmith).
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*
|
||||
* SYS_LED and COL_x are open-drain, output logic is inverted.
|
||||
*
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
@ -21,22 +19,42 @@
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
#include "axp2101.h"
|
||||
#include "backlight.h"
|
||||
#include "batt.h"
|
||||
#include "eeprom.h"
|
||||
#include "fifo.h"
|
||||
#include "keyboard.h"
|
||||
#include "regs.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PTD */
|
||||
|
||||
enum i2cs_state {
|
||||
//I2CS_STATE_HALT,
|
||||
I2CS_STATE_IDLE,
|
||||
I2CS_STATE_REG_REQUEST,
|
||||
I2CS_STATE_REG_ANSWER
|
||||
};
|
||||
/* USER CODE END PTD */
|
||||
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PD */
|
||||
//#define DEFAULT_LCD_BL (205) // ~40% PWM@7.81kHz (9 bits resolution)
|
||||
//#define DEFAULT_KBD_BL (20) // ~4% PWM@7.81kHz (9 bits resolution)
|
||||
#define DEFAULT_LCD_BL (3) //step-4 (~50%)
|
||||
#define DEFAULT_KBD_BL (0) //step-1 (0%)
|
||||
|
||||
#define I2CS_REARM_TIMEOUT 500
|
||||
/* USER CODE END PD */
|
||||
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* USER CODE BEGIN PM */
|
||||
|
||||
#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)
|
||||
#define DEBUG_UART_MSG2(d,sz, swp) uart_rawdata_write(d,sz,swp)
|
||||
#endif
|
||||
/* USER CODE END PM */
|
||||
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
@ -51,7 +69,27 @@ UART_HandleTypeDef huart1;
|
||||
UART_HandleTypeDef huart3;
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
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;
|
||||
#ifdef DEBUG
|
||||
static const uint8_t hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
#endif
|
||||
|
||||
static uint8_t i2cs_r_buff[2];
|
||||
static volatile uint8_t i2cs_r_idx = 0;
|
||||
static uint8_t i2cs_w_buff[31 + 1]; // The last one must be only a 0 value
|
||||
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;
|
||||
volatile uint8_t pmu_irq = 0;
|
||||
static uint32_t pmu_online = 0;
|
||||
|
||||
uint8_t io_matrix[9] = {0}; //for IO matrix,last byte is the restore key(c64 only)
|
||||
uint8_t js_bits = 0xFF; // c64 joystick bits
|
||||
/* USER CODE END PV */
|
||||
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
@ -67,11 +105,170 @@ static void MX_TIM1_Init(void);
|
||||
static void MX_TIM3_Init(void);
|
||||
static void MX_TIM2_Init(void);
|
||||
/* USER CODE BEGIN PFP */
|
||||
|
||||
//static void lock_cb(uint8_t caps_changed, uint8_t num_changed);
|
||||
static void key_cb(char key, enum key_state state);
|
||||
static void hw_check_HP_presence(void);
|
||||
static void sync_bat(void);
|
||||
static void check_pmu_int(void);
|
||||
/* USER CODE END PFP */
|
||||
|
||||
/* Private user code ---------------------------------------------------------*/
|
||||
/* USER CODE BEGIN 0 */
|
||||
extern void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
|
||||
if (htim == &htim2) {
|
||||
systicks_counter += 1;
|
||||
i2cs_rearm_counter += 1;
|
||||
}
|
||||
}
|
||||
|
||||
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 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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_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_BAT) {
|
||||
i2cs_w_buff[1] = reg_get_value(REG_ID_BAT);
|
||||
} 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 {
|
||||
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 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
if (reg == REG_ID_BKL) { // We wait an another byte for these registers
|
||||
if (is_write) {
|
||||
HAL_I2C_Slave_Sequential_Receive_IT(hi2c, i2cs_r_buff + i2cs_r_idx, 1, I2C_NEXT_FRAME); // This write the second received byte to i2cs_r_buff[1]
|
||||
}
|
||||
} else if (reg == REG_ID_BK2) {
|
||||
if (is_write) {
|
||||
HAL_I2C_Slave_Sequential_Receive_IT(hi2c, i2cs_r_buff + i2cs_r_idx, 1, I2C_NEXT_FRAME); // This write the second received byte to i2cs_r_buff[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*extern void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c) {
|
||||
if (hi2c == &hi2c1) {
|
||||
if (i2cs_state == I2CS_STATE_REG_ANSWER) {
|
||||
if (++i2cs_w_idx < i2cs_w_len) {
|
||||
HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, i2cs_w_buff + i2cs_w_idx, 1, I2C_NEXT_FRAME); // This write the next answer byte on I2C bus
|
||||
} else {
|
||||
i2cs_w_buff[31] = 0;
|
||||
HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, &i2cs_w_buff[31], 1, I2C_NEXT_FRAME); // send a 0 value to avoid stalling - TODO: usefull? can we use I2C_LAST_FRAME instead?
|
||||
}
|
||||
|
||||
i2cs_rearm_counter = 0;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
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(); //TODO: replace with dedicated, non-blocking, error handler
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void uart_rawdata_write(uint32_t c, size_t s, uint8_t swap) {
|
||||
uint8_t r[4];
|
||||
uint32_t v = swap ? __REV(c) : c;
|
||||
|
||||
HAL_UART_Transmit(&huart1, (uint8_t*)"0x", 2, 40);
|
||||
for (size_t i = 0; i < s; i++) {
|
||||
uint8_t index = swap ? (uint8_t)(4-s+i) : (uint8_t)i;
|
||||
r[0] = hexmap[(((uint8_t*)&v)[index] & 0xF0) >> 4];
|
||||
r[1] = hexmap[((uint8_t*)&v)[index] & 0x0F];
|
||||
HAL_UART_Transmit(&huart1, r, 2, 40);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void flash_one_time(uint32_t ts, uint8_t restore_status) {
|
||||
for (size_t i = 0; i < ts; i++) {
|
||||
LL_IWDG_ReloadCounter(IWDG);
|
||||
LL_GPIO_ResetOutputPin(SYS_LED_GPIO_Port, SYS_LED_Pin);
|
||||
HAL_Delay(400);
|
||||
LL_GPIO_SetOutputPin(SYS_LED_GPIO_Port, SYS_LED_Pin);
|
||||
HAL_Delay(200);
|
||||
}
|
||||
|
||||
if (restore_status)
|
||||
LL_GPIO_ResetOutputPin(SYS_LED_GPIO_Port, SYS_LED_Pin);
|
||||
else
|
||||
LL_GPIO_SetOutputPin(SYS_LED_GPIO_Port, SYS_LED_Pin);
|
||||
}
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
@ -83,7 +280,7 @@ int main(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
int32_t result = 0;
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/* MCU Configuration--------------------------------------------------------*/
|
||||
@ -115,15 +312,151 @@ int main(void)
|
||||
MX_TIM2_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
|
||||
LL_GPIO_ResetOutputPin(SYS_LED_GPIO_Port, SYS_LED_Pin); // I'm alive!
|
||||
|
||||
// Start the systick timer
|
||||
if (HAL_TIM_Base_Start_IT(&htim2) != HAL_OK)
|
||||
Error_Handler();
|
||||
|
||||
// EEPROM emulation init
|
||||
if (EEPROM_Init() != EEPROM_SUCCESS)
|
||||
Error_Handler();
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("EEPROM init\n\r");
|
||||
#endif
|
||||
|
||||
// Check EEPROM first run
|
||||
EEPROM_ReadVariable(EEPROM_VAR_ID, (EEPROM_Value*)&result);
|
||||
if ((uint16_t)result != 0xCA1C) {
|
||||
EEPROM_WriteVariable(EEPROM_VAR_BCKL, (EEPROM_Value)(uint16_t)((DEFAULT_LCD_BL << 8) | DEFAULT_KBD_BL), EEPROM_SIZE16);
|
||||
EEPROM_WriteVariable(EEPROM_VAR_KBD, (EEPROM_Value)(uint16_t)((10 << 8) | 5), EEPROM_SIZE16);
|
||||
EEPROM_WriteVariable(EEPROM_VAR_CFG, (EEPROM_Value)(uint16_t)(CFG_OVERFLOW_INT | CFG_KEY_INT | CFG_USE_MODS | CFG_REPORT_MODS), EEPROM_SIZE16);
|
||||
EEPROM_WriteVariable(EEPROM_VAR_ID, (EEPROM_Value)(uint16_t)0xCA1C, EEPROM_SIZE16);
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("EEPROM first start!\n\r");
|
||||
#endif
|
||||
}
|
||||
|
||||
// I2C-Pico interface registers
|
||||
reg_init();
|
||||
if (HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
|
||||
Error_Handler();
|
||||
HAL_Delay(10);
|
||||
|
||||
// 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) {
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("PMU ID: ");
|
||||
DEBUG_UART_MSG2((uint32_t)result, 1, 0);
|
||||
DEBUG_UART_MSG("\n\r");
|
||||
#endif
|
||||
pmu_online = 1;
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("PMU not online!\n\r");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Start LCD and KBD backlight PWM
|
||||
lcd_backlight_off();
|
||||
if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) != HAL_OK)
|
||||
Error_Handler();
|
||||
kbd_backlight_on();
|
||||
if (HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3) != HAL_OK)
|
||||
Error_Handler();
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("Bckl params: ");
|
||||
DEBUG_UART_MSG2(((uint32_t)result >> 8), 1, 1);
|
||||
DEBUG_UART_MSG(", ");
|
||||
DEBUG_UART_MSG2(((uint32_t)result & 0xFF), 1, 1);
|
||||
DEBUG_UART_MSG("\n\r");
|
||||
#endif
|
||||
|
||||
keyboard_set_key_callback(key_cb);
|
||||
|
||||
// Enable PICO power
|
||||
LL_GPIO_SetOutputPin(PICO_EN_GPIO_Port, PICO_EN_Pin);
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("Pico started\n\r");
|
||||
#endif
|
||||
|
||||
// Enable speaker Amp. power
|
||||
LL_GPIO_SetOutputPin(SP_AMP_EN_GPIO_Port, SP_AMP_EN_Pin);
|
||||
|
||||
HAL_Delay(1000);
|
||||
lcd_backlight_on();
|
||||
|
||||
// It is necessary to disable the detection function of the TS pin on the
|
||||
// board without the battery temperature detection function, otherwise it will
|
||||
// cause abnormal charging
|
||||
AXP2101_setSysPowerDownVoltage(2800);
|
||||
AXP2101_disableTSPinMeasure();
|
||||
// AXP2101_enableTemperatureMeasure();
|
||||
AXP2101_enableBattDetection();
|
||||
AXP2101_enableVbusVoltageMeasure();
|
||||
AXP2101_enableBattVoltageMeasure();
|
||||
AXP2101_enableSystemVoltageMeasure();
|
||||
|
||||
AXP2101_setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG);
|
||||
|
||||
AXP2101_disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
|
||||
AXP2101_clearIrqStatus();
|
||||
AXP2101_enableIRQ(XPOWERS_AXP2101_BAT_INSERT_IRQ |
|
||||
XPOWERS_AXP2101_BAT_REMOVE_IRQ | // BATTERY
|
||||
XPOWERS_AXP2101_VBUS_INSERT_IRQ |
|
||||
XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS
|
||||
XPOWERS_AXP2101_PKEY_SHORT_IRQ |
|
||||
XPOWERS_AXP2101_PKEY_LONG_IRQ | // POWER KEY
|
||||
XPOWERS_AXP2101_BAT_CHG_DONE_IRQ |
|
||||
XPOWERS_AXP2101_BAT_CHG_START_IRQ // CHARGE
|
||||
// XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ |
|
||||
// XPOWERS_AXP2101_PKEY_POSITIVE_IRQ | //POWER KEY
|
||||
);
|
||||
// setLowBatWarnThreshold Range: 5% ~ 20%
|
||||
// The following data is obtained from actual testing , Please see the description below for the test method.
|
||||
// 20% ~= 3.7v
|
||||
// 15% ~= 3.6v
|
||||
// 10% ~= 3.55V
|
||||
// 5% ~= 3.5V
|
||||
// 1% ~= 3.4V
|
||||
AXP2101_setLowBatWarnThreshold(20); // Set to trigger interrupt when reaching 20%
|
||||
|
||||
// setLowBatShutdownThreshold Range: 0% ~ 15%
|
||||
// The following data is obtained from actual testing , Please see the description below for the test method.
|
||||
// 15% ~= 3.6v
|
||||
// 10% ~= 3.55V
|
||||
// 5% ~= 3.5V
|
||||
// 1% ~= 3.4V
|
||||
AXP2101_setLowBatShutdownThreshold(5); //This is related to the battery charging and discharging logic. If you're not sure what you're doing, please don't modify it, as it could damage the battery.
|
||||
|
||||
keycb_start = 1;
|
||||
sync_bat();
|
||||
low_bat();
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Infinite loop */
|
||||
/* USER CODE BEGIN WHILE */
|
||||
while (1)
|
||||
{
|
||||
LL_IWDG_ReloadCounter(IWDG);
|
||||
/* USER CODE END WHILE */
|
||||
|
||||
/* USER CODE BEGIN 3 */
|
||||
// Save user registers in EEPROM if unsynced every 2.5s
|
||||
reg_sync();
|
||||
|
||||
// Re-arm I2CS in case of lost master signal
|
||||
if (i2cs_state != I2CS_STATE_IDLE && i2cs_rearm_counter > I2CS_REARM_TIMEOUT)
|
||||
i2cs_state = I2CS_STATE_IDLE;
|
||||
|
||||
check_pmu_int();
|
||||
keyboard_process();
|
||||
hw_check_HP_presence();
|
||||
//HAL_Delay(10);
|
||||
}
|
||||
/* USER CODE END 3 */
|
||||
}
|
||||
@ -207,7 +540,7 @@ static void MX_I2C1_Init(void)
|
||||
hi2c1.Instance = I2C1;
|
||||
hi2c1.Init.ClockSpeed = 10000;
|
||||
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
|
||||
hi2c1.Init.OwnAddress1 = 124;
|
||||
hi2c1.Init.OwnAddress1 = 62;
|
||||
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
|
||||
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
|
||||
hi2c1.Init.OwnAddress2 = 0;
|
||||
@ -270,7 +603,7 @@ static void MX_IWDG_Init(void)
|
||||
/* USER CODE END IWDG_Init 0 */
|
||||
|
||||
/* USER CODE BEGIN IWDG_Init 1 */
|
||||
|
||||
#ifndef DEBUG
|
||||
/* USER CODE END IWDG_Init 1 */
|
||||
LL_IWDG_Enable(IWDG);
|
||||
LL_IWDG_EnableWriteAccess(IWDG);
|
||||
@ -282,7 +615,7 @@ static void MX_IWDG_Init(void)
|
||||
|
||||
LL_IWDG_ReloadCounter(IWDG);
|
||||
/* USER CODE BEGIN IWDG_Init 2 */
|
||||
|
||||
#endif
|
||||
/* USER CODE END IWDG_Init 2 */
|
||||
|
||||
}
|
||||
@ -427,10 +760,10 @@ static void MX_TIM2_Init(void)
|
||||
|
||||
/* USER CODE END TIM2_Init 1 */
|
||||
htim2.Instance = TIM2;
|
||||
htim2.Init.Prescaler = 0;
|
||||
htim2.Init.Prescaler = 4-1;
|
||||
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim2.Init.Period = 1000;
|
||||
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4;
|
||||
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
|
||||
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
|
||||
{
|
||||
@ -525,7 +858,7 @@ static void MX_USART1_UART_Init(void)
|
||||
/* USER CODE END USART1_Init 0 */
|
||||
|
||||
/* USER CODE BEGIN USART1_Init 1 */
|
||||
|
||||
#ifdef DEBUG
|
||||
/* USER CODE END USART1_Init 1 */
|
||||
huart1.Instance = USART1;
|
||||
huart1.Init.BaudRate = 115200;
|
||||
@ -540,7 +873,7 @@ static void MX_USART1_UART_Init(void)
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN USART1_Init 2 */
|
||||
|
||||
#endif
|
||||
/* USER CODE END USART1_Init 2 */
|
||||
|
||||
}
|
||||
@ -558,7 +891,7 @@ static void MX_USART3_UART_Init(void)
|
||||
/* USER CODE END USART3_Init 0 */
|
||||
|
||||
/* USER CODE BEGIN USART3_Init 1 */
|
||||
|
||||
#ifdef UART_PICO_INTERFACE
|
||||
/* USER CODE END USART3_Init 1 */
|
||||
huart3.Instance = USART3;
|
||||
huart3.Init.BaudRate = 115200;
|
||||
@ -573,7 +906,7 @@ static void MX_USART3_UART_Init(void)
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN USART3_Init 2 */
|
||||
|
||||
#endif
|
||||
/* USER CODE END USART3_Init 2 */
|
||||
|
||||
}
|
||||
@ -680,7 +1013,283 @@ static void MX_GPIO_Init(void)
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 4 */
|
||||
/*
|
||||
static void lock_cb(uint8_t caps_changed, uint8_t num_changed) {
|
||||
//uint8_t do_int = 0;
|
||||
|
||||
if (caps_changed && reg_is_bit_set(REG_ID_CFG, CFG_CAPSLOCK_INT)) {
|
||||
reg_set_bit(REG_ID_INT, INT_CAPSLOCK);
|
||||
//do_int = 1;
|
||||
}
|
||||
|
||||
if (num_changed && reg_is_bit_set(REG_ID_CFG, CFG_NUMLOCK_INT)) {
|
||||
reg_set_bit(REG_ID_INT, INT_NUMLOCK);
|
||||
//do_int = 1;
|
||||
}
|
||||
|
||||
// int_pin can be a LED
|
||||
if (do_int) {
|
||||
port_pin_set_output_level(int_pin, 0);
|
||||
delay_ms(INT_DURATION_MS);
|
||||
port_pin_set_output_level(int_pin, 1);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static void key_cb(char key, enum key_state state) {
|
||||
if (keycb_start == 0) {
|
||||
fifo_flush();
|
||||
return;
|
||||
}
|
||||
|
||||
if (reg_is_bit_set(REG_ID_CFG, CFG_KEY_INT)) {
|
||||
reg_set_bit(REG_ID_INT, INT_KEY);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Serial1.println("key: 0x%02X/%d/%c, state: %d, blk: %d\r\n", key, key, key, state, reg_get_value(REG_ID_BKL));
|
||||
//HAL_UART_Transmit_IT(&huart1, HP_PLUG_MSG, HP_PLUG_MSG_LEN);
|
||||
#endif
|
||||
|
||||
const struct fifo_item item = {key, state};
|
||||
if (!fifo_enqueue(item)) {
|
||||
if (reg_is_bit_set(REG_ID_CFG, CFG_OVERFLOW_INT)) {
|
||||
reg_set_bit(REG_ID_INT, INT_OVERFLOW); // INT_OVERFLOW The interrupt was generated by FIFO overflow.
|
||||
}
|
||||
|
||||
if (reg_is_bit_set(REG_ID_CFG, CFG_OVERFLOW_ON)) fifo_enqueue_force(item);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
//Serial1.println(key);
|
||||
//HAL_UART_Transmit_IT(&huart1, HP_PLUG_MSG, HP_PLUG_MSG_LEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
__STATIC_INLINE void hw_check_HP_presence(void) {
|
||||
uint32_t v = LL_GPIO_IsInputPinSet(HP_DET_GPIO_Port, HP_DET_Pin);
|
||||
|
||||
if (v != head_phone_status) {
|
||||
if (v != 0) {
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("HeadPhone inserted\n\r");
|
||||
#endif
|
||||
LL_GPIO_ResetOutputPin(SP_AMP_EN_GPIO_Port, SP_AMP_EN_Pin);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("HeadPhone removed\n\r");
|
||||
#endif
|
||||
LL_GPIO_SetOutputPin(SP_AMP_EN_GPIO_Port, SP_AMP_EN_Pin);
|
||||
}
|
||||
|
||||
head_phone_status = v;
|
||||
}
|
||||
}
|
||||
|
||||
__STATIC_INLINE void sync_bat(void) {
|
||||
uint8_t pcnt;
|
||||
if (AXP2101_getBatteryPercent(&pcnt) != HAL_OK)
|
||||
return;
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("check_pmu_int: ");
|
||||
DEBUG_UART_MSG2((uint32_t)pcnt, 1, 0);
|
||||
DEBUG_UART_MSG("\n\r");
|
||||
#endif
|
||||
|
||||
if (pcnt > 100) { // disconnect
|
||||
pcnt = 0;
|
||||
} else { // battery connected
|
||||
if (AXP2101_isCharging())
|
||||
pcnt |= (1 << 7);
|
||||
low_bat();
|
||||
}
|
||||
|
||||
reg_set_value(REG_ID_BAT, pcnt);
|
||||
}
|
||||
|
||||
__STATIC_INLINE void check_pmu_int(void) {
|
||||
if (!pmu_online)
|
||||
return;
|
||||
|
||||
uint8_t pcnt;
|
||||
|
||||
if (uptime_ms() - pmu_check_counter > 20000) {
|
||||
pmu_check_counter = uptime_ms(); // reset time
|
||||
AXP2101_getBatteryPercent(&pcnt);
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("check_pmu_int: ");
|
||||
DEBUG_UART_MSG2((uint32_t)pcnt, 1, 0);
|
||||
DEBUG_UART_MSG("\n\r");
|
||||
#endif
|
||||
|
||||
if (pcnt > 100) { // disconnect
|
||||
pcnt = 0;
|
||||
} else { // battery connected
|
||||
if (AXP2101_isCharging())
|
||||
pcnt |= (1 << 7);
|
||||
low_bat();
|
||||
}
|
||||
|
||||
reg_set_value(REG_ID_BAT,pcnt);
|
||||
}
|
||||
|
||||
if (pmu_irq) {
|
||||
pmu_irq = 0; // Reset interrupt flag
|
||||
|
||||
// Get PMU Interrupt Status Register
|
||||
uint32_t status;
|
||||
AXP2101_getIrqStatus(&status);
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("PMU IRQ status: ");
|
||||
DEBUG_UART_MSG2(status, 4, 1);
|
||||
DEBUG_UART_MSG("\n\r");
|
||||
#endif
|
||||
|
||||
/*
|
||||
// When the set low-voltage battery percentage warning threshold is reached,
|
||||
// set the threshold through getLowBatWarnThreshold( 5% ~ 20% )
|
||||
if (PMU.isDropWarningLevel2Irq()) {
|
||||
Serial1.println("isDropWarningLevel2");
|
||||
//report_bat();
|
||||
}
|
||||
*/
|
||||
|
||||
// When the set low-voltage battery percentage shutdown threshold is reached
|
||||
// set the threshold through setLowBatShutdownThreshold()
|
||||
//This is related to the battery charging and discharging logic. If you're not sure what you're doing, please don't modify it, as it could damage the battery.
|
||||
if (AXP2101_isDropWarningLevel1Irq()) {
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("PMU: isDropWarningLevel1\n\r");
|
||||
#endif
|
||||
//report_bat();
|
||||
//
|
||||
AXP2101_shutdown();
|
||||
}
|
||||
/*if (PMU.isGaugeWdtTimeoutIrq()) {
|
||||
Serial1.println("isWdtTimeout");
|
||||
}
|
||||
if (PMU.isBatChargerOverTemperatureIrq()) {
|
||||
Serial1.println("isBatChargeOverTemperature");
|
||||
}
|
||||
if (PMU.isBatWorkOverTemperatureIrq()) {
|
||||
Serial1.println("isBatWorkOverTemperature");
|
||||
}
|
||||
if (PMU.isBatWorkUnderTemperatureIrq()) {
|
||||
Serial1.println("isBatWorkUnderTemperature");
|
||||
}
|
||||
if (PMU.isVbusInsertIrq()) {
|
||||
Serial1.println("isVbusInsert");
|
||||
}*/
|
||||
if (AXP2101_isVbusRemoveIrq()) {
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("PMU: isVbusRemove\n\r");
|
||||
#endif
|
||||
stop_chg();
|
||||
}
|
||||
if (AXP2101_isBatInsertIrq()) {
|
||||
AXP2101_getBatteryPercent(&pcnt);
|
||||
if (pcnt > 100) { // disconnect
|
||||
pcnt = 0;
|
||||
} else { // battery connected
|
||||
pcnt |= (1 << 7);
|
||||
}
|
||||
reg_set_value(REG_ID_BAT, pcnt);
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("PMU: isBatInsert\n\r");
|
||||
#endif
|
||||
}
|
||||
if (AXP2101_isBatRemoveIrq()) {
|
||||
reg_set_value(REG_ID_BAT,0);
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("PMU: isBatRemove\n\r");
|
||||
#endif
|
||||
stop_chg();
|
||||
}
|
||||
|
||||
/*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();
|
||||
}*/
|
||||
|
||||
if (AXP2101_isPekeyLongPressIrq()) {
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("PMU: isPekeyLongPress\n\r");
|
||||
#endif
|
||||
//Serial1.println("write pmu data buffer .");
|
||||
//uint8_t data[4] = {1, 2, 3, 4};
|
||||
//PMU.writeDataBuffer(data, XPOWERS_AXP2101_DATA_BUFFER_SIZE);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/*if (PMU.isPekeyNegativeIrq()) {
|
||||
Serial1.println("isPekeyNegative");
|
||||
}
|
||||
if (PMU.isPekeyPositiveIrq()) {
|
||||
Serial1.println("isPekeyPositive");
|
||||
}
|
||||
|
||||
if (PMU.isLdoOverCurrentIrq()) {
|
||||
Serial1.println("isLdoOverCurrentIrq");
|
||||
}
|
||||
if (PMU.isBatfetOverCurrentIrq()) {
|
||||
Serial1.println("isBatfetOverCurrentIrq");
|
||||
}*/
|
||||
if (AXP2101_isBatChargeDoneIrq()) {
|
||||
AXP2101_getBatteryPercent(&pcnt);
|
||||
if (pcnt > 100) { // disconnect
|
||||
pcnt = 0;
|
||||
} else { // battery connected
|
||||
pcnt |= (1 << 7);
|
||||
}
|
||||
reg_set_value(REG_ID_BAT,pcnt);
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("PMU: isBatChagerDone\n\r");
|
||||
#endif
|
||||
stop_chg();
|
||||
}
|
||||
if (AXP2101_isBatChargeStartIrq()) {
|
||||
AXP2101_getBatteryPercent(&pcnt);
|
||||
if (pcnt > 100) { // disconnect
|
||||
pcnt = 0;
|
||||
} else { // battery connected
|
||||
pcnt |= (1 << 7);
|
||||
}
|
||||
reg_set_value(REG_ID_BAT,pcnt);
|
||||
#ifdef DEBUG
|
||||
DEBUG_UART_MSG("PMU: isBatChagerStart\n\r");
|
||||
#endif
|
||||
if(AXP2101_isBatteryConnect())
|
||||
start_chg();
|
||||
}
|
||||
/*if (PMU.isBatDieOverTemperatureIrq()) {
|
||||
Serial1.println("isBatDieOverTemperature");
|
||||
}
|
||||
if (PMU.isChagerOverTimeoutIrq()) {
|
||||
Serial1.println("isChagerOverTimeout");
|
||||
}
|
||||
if (PMU.isBatOverVoltageIrq()) {
|
||||
Serial1.println("isBatOverVoltage");
|
||||
}*/
|
||||
|
||||
// Clear PMU Interrupt Status Register
|
||||
AXP2101_clearIrqStatus();
|
||||
}
|
||||
}
|
||||
/* USER CODE END 4 */
|
||||
|
||||
/**
|
||||
@ -692,8 +1301,9 @@ void Error_Handler(void)
|
||||
/* USER CODE BEGIN Error_Handler_Debug */
|
||||
/* User can add his own implementation to report the HAL error return state */
|
||||
__disable_irq();
|
||||
while (1)
|
||||
{
|
||||
while (1) {
|
||||
//LL_GPIO_TogglePin(SYS_LED_GPIO_Port, SYS_LED_Pin);
|
||||
HAL_Delay(500);
|
||||
}
|
||||
/* USER CODE END Error_Handler_Debug */
|
||||
}
|
||||
|
110
Core/Src/regs.c
Normal file
110
Core/Src/regs.c
Normal file
@ -0,0 +1,110 @@
|
||||
#include "regs.h"
|
||||
#include "main.h"
|
||||
#include "eeprom.h"
|
||||
#include "backlight.h"
|
||||
|
||||
|
||||
static uint8_t regs[REG_ID_LAST] = {0};
|
||||
static uint8_t regs_unsync[REG_ID_LAST] = {0};
|
||||
static uint32_t eeprom_refresh_counter;
|
||||
|
||||
inline uint8_t reg_get_value(enum reg_id reg) {
|
||||
if (reg >= REG_ID_LAST)
|
||||
return 0;
|
||||
|
||||
return regs[reg];
|
||||
}
|
||||
|
||||
inline uint8_t* reg_raw_access(void) {
|
||||
return regs;
|
||||
}
|
||||
|
||||
inline void reg_set_value(enum reg_id reg, uint8_t value) {
|
||||
if (reg >= REG_ID_LAST)
|
||||
return;
|
||||
|
||||
regs[reg] = value;
|
||||
regs_unsync[reg] = 1;
|
||||
eeprom_refresh_counter = uptime_ms();
|
||||
}
|
||||
|
||||
inline uint8_t reg_is_bit_set(enum reg_id reg, uint8_t bit) {
|
||||
if (reg >= REG_ID_LAST)
|
||||
return 0;
|
||||
|
||||
return regs[reg] & bit;
|
||||
}
|
||||
|
||||
inline void reg_set_bit(enum reg_id reg, uint8_t bit) {
|
||||
if (reg >= REG_ID_LAST)
|
||||
return;
|
||||
|
||||
regs[reg] |= bit;
|
||||
regs_unsync[reg] = 1;
|
||||
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. |
|
||||
*/
|
||||
void reg_init(void) {
|
||||
uint16_t buff;
|
||||
|
||||
EEPROM_ReadVariable(EEPROM_VAR_CFG, (EEPROM_Value*)&buff);
|
||||
regs[REG_ID_CFG] = (uint8_t)(buff & 0xFF);
|
||||
|
||||
EEPROM_ReadVariable(EEPROM_VAR_KBD, (EEPROM_Value*)&buff);
|
||||
regs[REG_ID_DEB] = (uint8_t)((buff >> 8) & 0xFF);
|
||||
regs[REG_ID_FRQ] = (uint8_t)(buff & 0xFF);
|
||||
|
||||
EEPROM_ReadVariable(EEPROM_VAR_BCKL, (EEPROM_Value*)&buff);
|
||||
regs[REG_ID_BKL] = (uint8_t)((buff >> 8) & 0xFF);
|
||||
regs[REG_ID_BK2] = (uint8_t)(buff & 0xFF);
|
||||
|
||||
regs[REG_ID_BAT] = 0; //default .no battery ,no charging
|
||||
|
||||
eeprom_refresh_counter = uptime_ms();
|
||||
}
|
||||
|
||||
uint32_t reg_check_and_save_eeprom(void) {
|
||||
uint32_t result = EEPROM_SUCCESS;
|
||||
uint8_t need_save = 0;
|
||||
|
||||
for (size_t i = 0; i < REG_ID_LAST; i++)
|
||||
if (regs_unsync[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], EEPROM_SIZE16);
|
||||
|
||||
if (regs_unsync[REG_ID_DEB] == 1 || regs_unsync[REG_ID_FRQ] == 1)
|
||||
result |= EEPROM_WriteVariable(EEPROM_VAR_KBD, (EEPROM_Value)(uint16_t)((regs[REG_ID_DEB] << 8) | regs[REG_ID_FRQ]), EEPROM_SIZE16);
|
||||
|
||||
if (regs_unsync[REG_ID_BKL] == 1 || regs_unsync[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);
|
||||
|
||||
for (size_t i = 0; i < REG_ID_LAST; i++)
|
||||
regs_unsync[i] = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void reg_sync(void) {
|
||||
if (uptime_ms() > (eeprom_refresh_counter + 1500)) {
|
||||
reg_check_and_save_eeprom();
|
||||
eeprom_refresh_counter = uptime_ms();
|
||||
}
|
||||
}
|
@ -113,9 +113,9 @@ void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
|
||||
/* Peripheral clock enable */
|
||||
__HAL_RCC_I2C1_CLK_ENABLE();
|
||||
/* I2C1 interrupt Init */
|
||||
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 4, 0);
|
||||
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 2, 0);
|
||||
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
|
||||
HAL_NVIC_SetPriority(I2C1_ER_IRQn, 4, 0);
|
||||
HAL_NVIC_SetPriority(I2C1_ER_IRQn, 2, 0);
|
||||
HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
|
||||
/* USER CODE BEGIN I2C1_MspInit 1 */
|
||||
|
||||
|
@ -213,7 +213,7 @@ void EXTI9_5_IRQHandler(void)
|
||||
{
|
||||
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_9);
|
||||
/* USER CODE BEGIN LL_EXTI_LINE_9 */
|
||||
|
||||
pmu_irq = 1;
|
||||
/* USER CODE END LL_EXTI_LINE_9 */
|
||||
}
|
||||
/* USER CODE BEGIN EXTI9_5_IRQn 1 */
|
||||
|
@ -7,6 +7,7 @@ The main differences with the original are followings:
|
||||
|
||||
- drastic reduction in the STM32's electricity consumption when running (~3.5 mA),
|
||||
- removed stm32duino dependencies (use STM32HAL instead, maybe I'll switch to libopencm3 someday...),
|
||||
- clean up (in progress) to reduce binary size (~25 KB) and allow more features to be implemented,
|
||||
- added configuration saving solution (using internal flash, including backlight option),
|
||||
- rewriten or added some debug UART interface message,
|
||||
- lighten AXP2101 PMIC driver.
|
||||
|
@ -6,7 +6,7 @@ File.Version=6
|
||||
GPIO.groupedBy=Group By Peripherals
|
||||
I2C1.ClockSpeed=10000
|
||||
I2C1.IPParameters=OwnAddress,ClockSpeed
|
||||
I2C1.OwnAddress=62
|
||||
I2C1.OwnAddress=0x1F
|
||||
I2C2.I2C_Mode=I2C_Standard
|
||||
I2C2.IPParameters=OwnAddress,I2C_Mode
|
||||
I2C2.OwnAddress=0
|
||||
@ -97,8 +97,8 @@ NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.EXTI9_5_IRQn=true\:3\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.ForceEnableDMAVector=true
|
||||
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.I2C1_ER_IRQn=true\:4\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.I2C1_EV_IRQn=true\:4\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.I2C1_ER_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.I2C1_EV_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true
|
||||
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
@ -456,11 +456,11 @@ TIM1.Period=800
|
||||
TIM1.Prescaler=0
|
||||
TIM1.Pulse-PWM\ Generation1\ CH1=0
|
||||
TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
|
||||
TIM2.ClockDivision=TIM_CLOCKDIVISION_DIV4
|
||||
TIM2.ClockDivision=TIM_CLOCKDIVISION_DIV1
|
||||
TIM2.CounterMode=TIM_COUNTERMODE_UP
|
||||
TIM2.IPParameters=AutoReloadPreload,CounterMode,Prescaler,ClockDivision,Period
|
||||
TIM2.Period=1000
|
||||
TIM2.Prescaler=0
|
||||
TIM2.Prescaler=4-1
|
||||
TIM3.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
|
||||
TIM3.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
||||
TIM3.IPParameters=Channel-PWM Generation3 CH3,Prescaler,AutoReloadPreload,Pulse-PWM Generation3 CH3,OCMode_PWM-PWM Generation3 CH3,Period
|
||||
|
Loading…
x
Reference in New Issue
Block a user