From 341c71031ccc950a4022901470355f46f1e9f525 Mon Sep 17 00:00:00 2001 From: DiSlord Date: Wed, 3 Mar 2021 22:16:21 +0300 Subject: [PATCH] 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 --- adc.c | 73 +++++++++++++++++++--------- adc_F303.c | 53 +++++++++++--------- ui.c | 139 ++++++++++++++++++++++++----------------------------- 3 files changed, 141 insertions(+), 124 deletions(-) diff --git a/adc.c b/adc.c index 5123d20..a55b4a8 100644 --- a/adc.c +++ b/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; + 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; } diff --git a/adc_F303.c b/adc_F303.c index 556ec6a..8cbfdc7 100644 --- a/adc_F303.c +++ b/adc_F303.c @@ -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; + 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) diff --git a/ui.c b/ui.c index 8d50adc..d208f25 100644 --- a/ui.c +++ b/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; }