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 b10de07..4bafd45 100644 --- a/main.c +++ b/main.c @@ -52,6 +52,7 @@ int8_t sweep_enabled = TRUE; int8_t cal_auto_interpolate = TRUE; int8_t redraw_requested = FALSE; int8_t stop_the_world = FALSE; +int16_t vbat = 0; static THD_WORKING_AREA(waThread1, 640); static THD_FUNCTION(Thread1, arg) @@ -74,6 +75,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 */ @@ -1742,6 +1750,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[] = @@ -1779,6 +1794,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..655e78e 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 @@ -350,10 +352,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) {