diff --git a/adc.c b/adc.c index be65e46..1da498d 100644 --- a/adc.c +++ b/adc.c @@ -25,6 +25,7 @@ #define ADC_TR(low, high) (((uint32_t)(high) << 16U) | \ (uint32_t)(low)) #define ADC_SMPR_SMP_1P5 0U /**< @brief 14 cycles conversion time */ +#define ADC_SMPR_SMP_239P5 7U /**< @brief 252 cycles conversion time. */ #define ADC_CFGR1_RES_12BIT (0U << 3U) void adc_init(void) @@ -61,7 +62,7 @@ uint16_t adc_single_read(ADC_TypeDef *adc, uint32_t chsel) adc->ISR = adc->ISR; adc->IER = 0; adc->TR = ADC_TR(0, 0); - adc->SMPR = ADC_SMPR_SMP_1P5; + adc->SMPR = ADC_SMPR_SMP_239P5; adc->CFGR1 = ADC_CFGR1_RES_12BIT; adc->CHSELR = chsel; @@ -74,6 +75,32 @@ uint16_t adc_single_read(ADC_TypeDef *adc, uint32_t chsel) return adc->DR; } +int16_t adc_vbat_read(ADC_TypeDef *adc) +{ +#define ADC_FULL_SCALE 3300 +#define VBAT_DIODE_VF 500 +#define VREFINT_CAL (*((uint16_t*)0x1FFFF7BA)) + float vbat = 0; + float vrefint = 0; + + ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_VBATEN; + // VREFINT == ADC_IN17 + vrefint = adc_single_read(adc, ADC_CHSELR_CHSEL17); + // VBAT == ADC_IN18 + // VBATEN enables resiter devider circuit. It consume vbat power. + vbat = adc_single_read(adc, ADC_CHSELR_CHSEL18); + ADC->CCR &= ~(ADC_CCR_VREFEN | ADC_CCR_VBATEN); + + uint16_t vbat_raw = (ADC_FULL_SCALE * VREFINT_CAL * vbat * 2 / (vrefint * ((1<<12)-1))); + if (vbat_raw < 100) { + // maybe D2 is not installed + return -1; + } + + return vbat_raw + VBAT_DIODE_VF; + +} + void adc_start_analog_watchdogd(ADC_TypeDef *adc, uint32_t chsel) { uint32_t cfgr1; diff --git a/main.c b/main.c index 06ef386..05f0614 100644 --- a/main.c +++ b/main.c @@ -56,6 +56,7 @@ int8_t sweep_once = FALSE; int8_t cal_auto_interpolate = TRUE; int8_t redraw_requested = FALSE; int8_t stop_the_world = FALSE; +int16_t vbat = 0; BaseSequentialStream *saved_chp; @@ -84,6 +85,13 @@ static THD_FUNCTION(Thread1, arg) ui_process(); } + if (vbat != -1) { + adc_stop(ADC1); + vbat = adc_vbat_read(ADC1); + touch_start_watchdog(); + draw_battery_status(); + } + /* calculate trace coordinates */ plot_into_index(measured); /* plot trace as raster */ @@ -1648,6 +1656,18 @@ static void cmd_touchtest(BaseSequentialStream *chp, int argc, char *argv[]) } +static void cmd_battery(BaseSequentialStream *chp, int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + adc_stop(ADC1); + int v = adc_vbat_read(ADC1); + chprintf(chp, "%d\r\n", v); + touch_start_watchdog(); +} + + static void cmd_frequencies(BaseSequentialStream *chp, int argc, char *argv[]) { int i; @@ -1800,6 +1820,13 @@ static void cmd_version(BaseSequentialStream *chp, int argc, char *argv[]) chprintf(chp, "%s\r\n", NANOVNA_VERSION); } +static void cmd_vbat(BaseSequentialStream *chp, int argc, char *argv[]) +{ + (void)argc; + (void)argv; + chprintf(chp, "%d mV\r\n", vbat); +} + static THD_WORKING_AREA(waThread2, /* cmd_* max stack size + alpha */410); static const ShellCommand commands[] = @@ -1828,6 +1855,7 @@ static const ShellCommand commands[] = { "test", cmd_test }, { "touchcal", cmd_touchcal }, { "touchtest", cmd_touchtest }, + { "battery", cmd_battery }, { "pause", cmd_pause }, { "resume", cmd_resume }, { "cal", cmd_cal }, @@ -1837,6 +1865,7 @@ static const ShellCommand commands[] = { "marker", cmd_marker }, { "edelay", cmd_edelay }, { "capture", cmd_capture }, + { "vbat", cmd_vbat }, { NULL, NULL } }; diff --git a/nanovna.h b/nanovna.h index 4ddebe4..626eac4 100644 --- a/nanovna.h +++ b/nanovna.h @@ -194,6 +194,7 @@ void set_trace_refpos(int t, float refpos); float get_trace_scale(int t); float get_trace_refpos(int t); const char *get_trace_typename(int t); +void draw_battery_status(void); void set_electrical_delay(float picoseconds); float get_electrical_delay(void); @@ -230,6 +231,7 @@ void marker_position(int m, int t, int *x, int *y); int search_nearest_index(int x, int y, int t); extern int8_t redraw_requested; +extern int16_t vbat; /* * ili9341.c @@ -313,6 +315,8 @@ int config_recall(void); void clear_all_config_prop_data(void); +int16_t adc_vbat_read(ADC_TypeDef *adc); + /* * ui.c */ @@ -350,10 +354,21 @@ uint16_t adc_single_read(ADC_TypeDef *adc, uint32_t chsel); void adc_start_analog_watchdogd(ADC_TypeDef *adc, uint32_t chsel); void adc_stop(ADC_TypeDef *adc); void adc_interrupt(ADC_TypeDef *adc); +int16_t adc_vbat_read(ADC_TypeDef *adc); /* * misclinous */ #define PULSE do { palClearPad(GPIOC, GPIOC_LED); palSetPad(GPIOC, GPIOC_LED);} while(0) +// convert vbat [mV] to battery indicator +static inline uint8_t vbat2bati(int16_t vbat) +{ + if (vbat < 3200) return 0; + if (vbat < 3450) return 25; + if (vbat < 3700) return 50; + if (vbat < 4100) return 75; + return 100; +} + /*EOF*/ diff --git a/plot.c b/plot.c index 4055870..2367372 100644 --- a/plot.c +++ b/plot.c @@ -1484,6 +1484,76 @@ draw_cal_status(void) } } +void +draw_battery_status(void) +{ + int w = 10, h = 14; + int x = 0, y = 0; + int i, c; + uint16_t *buf = spi_buffer; + uint8_t vbati = vbat2bati(vbat); + uint16_t col = vbati == 0 ? RGB565(0, 255, 0) : RGB565(0, 0, 240); + memset(spi_buffer, 0, w * h * 2); + + // battery head + x = 3; + buf[y * w + x++] = col; + buf[y * w + x++] = col; + buf[y * w + x++] = col; + buf[y * w + x++] = col; + + y++; + x = 3; + buf[y * w + x++] = col; + x++; x++; + buf[y * w + x++] = col; + + y++; + x = 1; + for (i = 0; i < 8; i++) + buf[y * w + x++] = col; + + for (c = 0; c < 3; c++) { + y++; + x = 1; + buf[y * w + x++] = col; + x++; x++; x++; x++; x++; x++; + buf[y * w + x++] = col; + + y++; + x = 1; + buf[y * w + x++] = col; + x++; + for (i = 0; i < 4; i++) + buf[y * w + x++] = ( ((c+1) * 25) >= (100 - vbati)) ? col : 0; + x++; + buf[y * w + x++] = col; + + y++; + x = 1; + buf[y * w + x++] = col; + x++; + for (i = 0; i < 4; i++) + buf[y * w + x++] = ( ((c+1) * 25) >= (100 - vbati)) ? col : 0; + x++; + buf[y * w + x++] = col; + } + + // battery foot + y++; + x = 1; + buf[y * w + x++] = col; + x++; x++; x++; x++; x++; x++; + buf[y * w + x++] = col; + + y++; + x = 1; + for (i = 0; i < 8; i++) + buf[y * w + x++] = col; + + ili9341_bulk(0, 1, w, h); +} + void request_to_redraw_grid(void) {