Rewrite touch subsystem

Unification for both platform
Possible if need use hardware touch module
Use cache for battery measure (made real measure once in 5s)
Not need start/stop watchdog in user calls
Removed_REF_marker
DiSlord 5 years ago committed by erikkaashoek
parent 62e7c27bb2
commit 341c71031c

73
adc.c

@ -68,36 +68,58 @@ uint16_t adc_single_read(uint32_t chsel)
VNA_ADC->CFGR1 = ADC_CFGR1_RES_12BIT;
VNA_ADC->CHSELR = chsel;
uint32_t result = 0;
uint32_t count = 1<<3; // Average count
do{
VNA_ADC->CR |= ADC_CR_ADSTART; // ADC conversion start.
while (VNA_ADC->CR & ADC_CR_ADSTART)
;
result+=VNA_ADC->DR;
}while(--count);
return result>>3;
VNA_ADC->CR |= ADC_CR_ADSTART; // ADC conversion start
while (VNA_ADC->CR & ADC_CR_ADSTART)
;
return VNA_ADC->DR;
}
int16_t adc_vbat_read(void)
{
// Vbat measure averange count = 2^VBAT_AVERAGE
#define VBAT_AVERAGE 4
// Measure vbat every 5 second
#define VBAT_MEASURE_INTERVAL 50000
static int16_t vbat_raw = 0;
static systime_t vbat_time = -VBAT_MEASURE_INTERVAL-1;
systime_t _time = chVTGetSystemTimeX();
if (_time - vbat_time < VBAT_MEASURE_INTERVAL)
goto return_cached;
vbat_time = _time;
// 13.9 Temperature sensor and internal reference voltage
// VREFINT_CAL calibrated on 3.3V, need get value in mV
#define ADC_FULL_SCALE 3300
#define VREFINT_CAL (*((uint16_t*)0x1FFFF7BA))
adc_stop();
uint32_t vrefint = 0;
uint32_t vbat = 0;
uint8_t restart_touch = 0;
if (VNA_ADC->CR & ADC_CR_ADSTART){
adc_stop_analog_watchdog();
restart_touch = 1;
}
ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_VBATEN;
// VREFINT == ADC_IN17
uint32_t vrefint = adc_single_read(ADC_CHSELR_CHSEL17);
// VBAT == ADC_IN18
// VBATEN enables resiter devider circuit. It consume vbat power.
uint32_t vbat = adc_single_read(ADC_CHSELR_CHSEL18);
for (uint16_t i = 0; i < 1<<VBAT_AVERAGE; i++){
// VREFINT == ADC_IN17
vrefint+= adc_single_read(ADC_CHSELR_CHSEL17);
// VBAT == ADC_IN18
// VBATEN enables resiter devider circuit. It consume vbat power.
vbat+= adc_single_read(ADC_CHSELR_CHSEL18);
}
vbat>>=VBAT_AVERAGE;
vrefint>>=VBAT_AVERAGE;
ADC->CCR &= ~(ADC_CCR_VREFEN | ADC_CCR_VBATEN);
touch_start_watchdog();
if (restart_touch)
adc_start_analog_watchdog();
// vbat_raw = (3300 * 2 * vbat / 4095) * (VREFINT_CAL / vrefint)
// uint16_t vbat_raw = (ADC_FULL_SCALE * VREFINT_CAL * (float)vbat * 2 / (vrefint * ((1<<12)-1)));
// For speed divide not on 4095, divide on 4096, get little error, but no matter
uint16_t vbat_raw = ((ADC_FULL_SCALE * 2 * vbat)>>12) * VREFINT_CAL / vrefint;
vbat_raw = ((ADC_FULL_SCALE * 2 * vbat)>>12) * VREFINT_CAL / vrefint;
return_cached:
if (vbat_raw < 100) {
// maybe D2 is not installed
return -1;
@ -105,7 +127,7 @@ int16_t adc_vbat_read(void)
return vbat_raw + config.vbat_offset;
}
void adc_start_analog_watchdogd(uint32_t chsel)
void adc_start_analog_watchdog(void)
{
uint32_t cfgr1;
@ -119,7 +141,7 @@ void adc_start_analog_watchdogd(uint32_t chsel)
VNA_ADC->IER = ADC_IER_AWDIE;
VNA_ADC->TR = ADC_TR(0, TOUCH_THRESHOLD);
VNA_ADC->SMPR = ADC_SMPR_SMP_1P5;
VNA_ADC->CHSELR = chsel;
VNA_ADC->CHSELR = ADC_TOUCH_Y;
/* ADC configuration and start.*/
VNA_ADC->CFGR1 = cfgr1;
@ -128,7 +150,7 @@ void adc_start_analog_watchdogd(uint32_t chsel)
VNA_ADC->CR |= ADC_CR_ADSTART;
}
void adc_stop(void)
void adc_stop_analog_watchdog(void)
{
if (VNA_ADC->CR & ADC_CR_ADEN) {
if (VNA_ADC->CR & ADC_CR_ADSTART) {
@ -200,9 +222,11 @@ uint16_t adc_multi_read(uint32_t chsel, uint16_t *result, uint32_t count)
int16_t adc_buf_read(uint32_t chsel, uint16_t *result, uint32_t count)
{
adc_stop();
uint8_t restart_touch = 0;
if (VNA_ADC->CR & ADC_CR_ADSTART){
adc_stop_analog_watchdog();
restart_touch = 1;
}
#if 0
// drive high to low on Y line (coordinates from left to right)
palSetPad(GPIOB, GPIOB_YN);
@ -218,7 +242,8 @@ int16_t adc_buf_read(uint32_t chsel, uint16_t *result, uint32_t count)
// palSetPadMode(GPIOA, 9, PAL_MODE_INPUT_ANALOG);
uint16_t res = adc_multi_read(chsel, result, count); // ADC_CHSELR_CHSEL9
#endif
touch_start_watchdog();
if (restart_touch)
adc_start_analog_watchdog();;
return res;
}

@ -93,9 +93,21 @@ uint16_t adc_single_read(uint32_t chsel)
int16_t adc_vbat_read(void)
{
// Vbat measure averange count = 2^VBAT_AVERAGE
#define VBAT_AVERAGE 4
// Measure vbat every 5 second
#define VBAT_MEASURE_INTERVAL 50000
static int16_t vbat_raw = 0;
static systime_t vbat_time = -VBAT_MEASURE_INTERVAL-1;
systime_t _time = chVTGetSystemTimeX();
if (_time - vbat_time < VBAT_MEASURE_INTERVAL)
goto return_cached;
vbat_time = _time;
uint16_t VREFINT_CAL = (*((uint16_t*)0x1FFFF7BA));
uint32_t vbat;
uint32_t vrefint;
uint32_t vrefint = 0;
uint32_t vbat = 0;
// const uint16_t V25 = 1750;// when V25=1.41V at ref 3.3V
// const uint16_t Avg_Slope = 5; //when avg_slope=4.3mV/C at ref 3.3V
// uint16_t temperature_cal1 = *((uint16_t*) ((uint32_t)0x1FFFF7B8U));
@ -108,19 +120,24 @@ int16_t adc_vbat_read(void)
// Vref+ = 3.3 V (tolerance: +-10 mV). */
// float avg_slope = ((float)(temperature_cal1 - temperature_cal2))/(110-25);
// float ts;
#ifndef F303_ADC_VREF_ALWAYS_ON
#ifndef F303_ADC_VREF_ALWAYS_ON
adcSTM32EnableVBAT(&ADCD1);
adcSTM32EnableVREF(&ADCD1);
// adcSTM32EnableTS(&ADCD1);
adcConvert(&ADCD1, &adcgrpcfgVBAT, samplesVBAT, ADC_GRP_BUF_DEPTH_VBAT);
#endif
for (uint16_t i = 0; i < 1<<VBAT_AVERAGE; i++){
adcConvert(&ADCD1, &adcgrpcfgVBAT, samplesVBAT, 1);
vbat+= samplesVBAT[0];
vrefint+= samplesVBAT[1];
}
vbat>>=VBAT_AVERAGE;
vrefint>>=VBAT_AVERAGE;
#ifndef F303_ADC_VREF_ALWAYS_ON
adcSTM32DisableVBAT(&ADCD1);
adcSTM32DisableVREF(&ADCD1);
// adcSTM32DisableTS(&ADCD1);
#else
adcConvert(&ADCD1, &adcgrpcfgVBAT, samplesVBAT, sizeof(samplesVBAT)/(sizeof(adcsample_t)*ADC_GRP_NUM_CHANNELS_VBAT));
#endif
vbat = samplesVBAT[0];
vrefint = samplesVBAT[1];
#endif
// ts = samplesVBAT[2];
// uint16_t vts = (ADC_FULL_SCALE * VREFINT_CAL * ts / (vrefint * ((1<<12)-1)));
// uint16_t TemperatureC2 = (uint16_t)((V25-ts)/Avg_Slope+25);
@ -129,7 +146,8 @@ int16_t adc_vbat_read(void)
// vbat_raw = (3300 * 2 * vbat / 4095) * (VREFINT_CAL / vrefint)
// uint16_t vbat_raw = (ADC_FULL_SCALE * VREFINT_CAL * (float)vbat * 2 / (vrefint * ((1<<12)-1)));
// For speed divide not on 4095, divide on 4096, get little error, but no matter
uint16_t vbat_raw = ((ADC_FULL_SCALE * 2 * vbat)>>12) * VREFINT_CAL / vrefint;
vbat_raw = ((ADC_FULL_SCALE * 2 * vbat)>>12) * VREFINT_CAL / vrefint;
return_cached:
if (vbat_raw < 100) {
// maybe D2 is not installed
return -1;
@ -137,25 +155,14 @@ int16_t adc_vbat_read(void)
return vbat_raw + config.vbat_offset;
}
void adc_start_analog_watchdogd(void)
void adc_start_analog_watchdog(void)
{
// adcStart(&ADCD2, NULL);
adcStartConversion(&ADCD2, &adcgrpcfgTouch, samples, 1);
}
void adc_stop(void)
void adc_stop_analog_watchdog(void)
{
#if 1
adcStopConversion(&ADCD2);
#else
if (ADC2->CR & ADC_CR_ADEN) {
if (ADC2->CR & ADC_CR_ADSTART) {
ADC2->CR |= ADC_CR_ADSTP;
while (ADC2->CR & ADC_CR_ADSTP)
;
}
}
#endif
}
static inline void adc_interrupt(void)

139
ui.c

@ -135,6 +135,9 @@ typedef struct {
#define EVT_TOUCH_PRESSED 2
#define EVT_TOUCH_RELEASED 3
#define EVT_TOUCH_LONGPRESS 4
#define TOUCH_INTERRUPT_ENABLED 1
static uint8_t touch_status_flag = 0;
static int8_t last_touch_status = EVT_TOUCH_NONE;
static int16_t last_touch_x;
static int16_t last_touch_y;
@ -220,9 +223,15 @@ static int btn_wait_release(void)
}
}
#define SOFTWARE_TOUCH
//*******************************************************************************
// Software Touch module
//*******************************************************************************
#ifdef SOFTWARE_TOUCH
// ADC read count for measure X and Y (2^N count)
#define TOUCH_X_N 4
#define TOUCH_Y_N 3
#define TOUCH_X_N 2
#define TOUCH_Y_N 2
static int
touch_measure_y(void)
{
@ -260,8 +269,14 @@ touch_measure_x(void)
do{v+=adc_single_read(ADC_TOUCH_X);}while(--cnt);
return v>>TOUCH_X_N;
}
// Manually measure touch event
static inline int
touch_status(void)
{
return adc_single_read(ADC_TOUCH_Y) > TOUCH_THRESHOLD;
}
void
static void
touch_prepare_sense(void)
{
// Set Y line as input
@ -277,35 +292,54 @@ touch_prepare_sense(void)
// chThdSleepMilliseconds(10); // Wait 10ms for denounce touch
}
void
static void
touch_start_watchdog(void)
{
touch_prepare_sense();
#ifdef TINYSA4
adc_start_analog_watchdogd();
#else
adc_start_analog_watchdogd(ADC_TOUCH_Y);
#endif
if (touch_status_flag&TOUCH_INTERRUPT_ENABLED) return;
touch_status_flag^=TOUCH_INTERRUPT_ENABLED;
adc_start_analog_watchdog();
}
static inline int
touch_status(void)
static void
touch_stop_watchdog(void)
{
return adc_single_read(ADC_TOUCH_Y) > TOUCH_THRESHOLD;
if (!(touch_status_flag&TOUCH_INTERRUPT_ENABLED)) return;
touch_status_flag^=TOUCH_INTERRUPT_ENABLED;
adc_stop_analog_watchdog();
}
// Touch panel timer check (check press frequency 20Hz)
static const GPTConfig gpt3cfg = {
20, // 200Hz timer clock. 200/10 = 20Hz touch check
NULL, // Timer callback.
0x0020, // CR2:MMS=02 to output TRGO
0
};
//
// Touch init function init timer 3 trigger adc for check touch interrupt, and run measure
//
static void touch_init(void){
// Prepare pin for measure touch event
touch_prepare_sense();
// Start touch interrupt, used timer_3 ADC check threshold:
gptStart(&GPTD3, &gpt3cfg); // Init timer 3
gptStartContinuous(&GPTD3, 10); // Start timer 3 vs timer 10 interval
touch_start_watchdog(); // Start ADC watchdog (measure by timer 3 interval and trigger interrupt if touch pressed)
}
// Main software touch function, should:
// set last_touch_x and last_touch_x
// return touch status
static int
touch_check(void)
{
touch_stop_watchdog();
int stat = touch_status();
if (stat) {
static int prev_x=0;
int y = touch_measure_y();
int x = touch_measure_x();
#define X_NOISE 5
if (x > prev_x - X_NOISE && x < prev_x + X_NOISE) // avoid noise
x = prev_x;
prev_x = x;
touch_prepare_sense();
if (touch_status())
{
@ -321,10 +355,8 @@ touch_check(void)
last_touch_x = mouse_x;
last_touch_y = mouse_y;
}
#endif
}
#else
}
#endif
#if 0 // Long press detection
systime_t ticks = chVTGetSystemTimeX();
@ -341,6 +373,10 @@ touch_check(void)
}
return stat ? EVT_TOUCH_DOWN : EVT_TOUCH_NONE;
}
//*******************************************************************************
// End Software Touch module
//*******************************************************************************
#endif // end SOFTWARE_TOUCH
void
touch_wait_release(void)
@ -368,8 +404,6 @@ void
touch_cal_exec(void)
{
int x1, x2, y1, y2;
adc_stop();
ili9341_set_foreground(LCD_FG_COLOR);
ili9341_set_background(LCD_BG_COLOR);
ili9341_clear_screen();
@ -401,7 +435,6 @@ touch_cal_exec(void)
config_save(); // Auto save touch calibration
//redraw_all();
touch_start_watchdog();
}
void
@ -409,8 +442,6 @@ touch_draw_test(void)
{
int x0, y0;
int x1, y1;
adc_stop();
ili9341_set_foreground(LCD_FG_COLOR);
ili9341_set_background(LCD_BG_COLOR);
@ -441,7 +472,6 @@ touch_draw_test(void)
} while (touch_check() != EVT_TOUCH_RELEASED);
}
}while (!(btn_check() & EVT_BUTTON_SINGLE_CLICK));
touch_start_watchdog();
}
@ -461,7 +491,6 @@ void
show_version(void)
{
int x = 5, y = 5, i = 0;
adc_stop();
ili9341_set_foreground(LCD_FG_COLOR);
ili9341_set_background(LCD_BG_COLOR);
@ -522,21 +551,17 @@ extern const char *states[];
(RCC->BDCR & STM32_RTCSEL_MASK) == STM32_RTCSEL_LSE ? 'E' : 'I');
ili9341_drawstring(buffer, x, y);
#endif
#if 1
#if 0
uint32_t vbat=adc_vbat_read();
plot_printf(buf, sizeof(buf), "Batt: %d.%03dV", vbat/1000, vbat%1000);
ili9341_drawstring(buf, x, y + FONT_STR_HEIGHT + 2);
#endif
}
touch_start_watchdog();
}
void
enter_dfu(void)
{
adc_stop();
int x = 5, y = 5;
ili9341_set_foreground(LCD_FG_COLOR);
ili9341_set_background(LCD_BG_COLOR);
@ -2692,8 +2717,6 @@ static void
ui_process_keypad(void)
{
int status;
adc_stop();
kp_index = 0;
while (TRUE) {
status = btn_check();
@ -2735,7 +2758,6 @@ ui_process_keypad(void)
// request_to_redraw_grid();
}
//redraw_all();
touch_start_watchdog();
}
static void
@ -2926,8 +2948,6 @@ touch_marker_select(int touch_x, int touch_y)
static
void ui_process_touch(void)
{
// awd_count++;
adc_stop();
int touch_x, touch_y;
int status = touch_check();
if (status == EVT_TOUCH_PRESSED || status == EVT_TOUCH_DOWN) {
@ -2958,7 +2978,6 @@ void ui_process_touch(void)
break;
}
}
touch_start_watchdog();
}
static int previous_button_state = 0;
@ -2989,6 +3008,7 @@ ui_process(void)
ui_process_touch();
operation_requested = OP_NONE;
}
touch_start_watchdog();
}
/* Triggered when the button is pressed or released. The LED4 is set to ON.*/
@ -3028,27 +3048,6 @@ static const EXTConfig extcfg = {
}
};
// Used for touch check interval
static const GPTConfig gpt3cfg = {
20, /* 20Hz timer clock.*/
NULL, /* Timer callback.*/
0x0020, /* CR2:MMS=02 to output TRGO */
0
};
#if 0
static void
test_touch(int *x, int *y)
{
adc_stop(ADC1);
*x = touch_measure_x();
*y = touch_measure_y();
touch_start_watchdog();
}
#endif
void
handle_touch_interrupt(void)
{
@ -3059,25 +3058,14 @@ void
ui_init()
{
adc_init();
/*
* Activates the EXT driver 1.
*/
// Activates the EXT driver 1.
extStart(&EXTD1, &extcfg);
#if 1
gptStart(&GPTD3, &gpt3cfg);
gptPolledDelay(&GPTD3, 10); /* Small delay.*/
gptStartContinuous(&GPTD3, 10);
#endif
touch_start_watchdog();
// Init touch subsystem
touch_init();
}
void wait_user(void)
{
adc_stop();
touch_wait_released();
#if 0
operation_requested = OP_NONE;
@ -3088,16 +3076,13 @@ void wait_user(void)
break;
}
#endif
touch_start_watchdog();
}
int check_touched(void)
{
int touched = false;
adc_stop();
if (touch_check() == EVT_TOUCH_RELEASED)
touched = true;
touch_start_watchdog();
return touched;
}

Loading…
Cancel
Save

Powered by TurnKey Linux.