From d2aed085a4321dad72de709b5742f708d13dc7cc Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sun, 10 Nov 2024 22:51:47 +0300 Subject: [PATCH 1/4] blackpill-f4: Implement ADC reading for VTRef on PA0 --- .../common/blackpill-f4/blackpill-f4.c | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.c b/src/platforms/common/blackpill-f4/blackpill-f4.c index 65b45afa502..402acd18af9 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.c +++ b/src/platforms/common/blackpill-f4/blackpill-f4.c @@ -39,9 +39,11 @@ #include #include #include +#include jmp_buf fatal_error_jmpbuf; volatile uint32_t magic[2] __attribute__((section(".noinit"))); +static void adc_init(); void platform_init(void) { @@ -144,6 +146,7 @@ void platform_init(void) /* By default, do not drive the SWD bus too fast. */ platform_max_frequency_set(2000000); + adc_init(); } void platform_nrst_set_val(bool assert) @@ -156,9 +159,41 @@ bool platform_nrst_get_val(void) return gpio_get(NRST_PORT, NRST_PIN) == 0; } +static void adc_init(void) +{ + rcc_periph_clock_enable(RCC_ADC1); + gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO0); + adc_power_off(ADC1); + adc_disable_scan_mode(ADC1); + adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR_SMP_480CYC); + adc_power_on(ADC1); +} + +static uint16_t platform_adc_read(void) +{ + const uint8_t channel = ADC_CHANNEL0; + adc_set_regular_sequence(ADC1, 1, &channel); + adc_start_conversion_regular(ADC1); + while (!adc_eoc(ADC1)) + continue; + uint32_t value = adc_read_regular(ADC1); + return value; +} + const char *platform_target_voltage(void) { - return "Unknown"; + static char msg[8] = "0.000V"; + const uint16_t vtref_sample = platform_adc_read(); + /* Convert 0-4095 full-scale code to 0-3300 integer millivolts */ + const uint32_t vtref_mv = vtref_sample * 3300U / 4095U; + /* Avoid printf_float */ + //utoa_upper(vtref_mv, vtref_dec, 10); + msg[0] = '0' + vtref_mv / 1000U; + msg[1] = '.'; + msg[2] = '0' + vtref_mv % 1000U / 100U; + msg[3] = '0' + vtref_mv % 100U / 10U; + msg[4] = '0' + vtref_mv % 10U; + return msg; } /* From db5f6dc98670acadece8e4498f7f78a7dfa44729 Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sun, 10 Nov 2024 22:54:44 +0300 Subject: [PATCH 2/4] blackpill-f4: Extract macros for VTRef pin and channel --- src/platforms/common/blackpill-f4/blackpill-f4.c | 6 +++--- src/platforms/common/blackpill-f4/blackpill-f4.h | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.c b/src/platforms/common/blackpill-f4/blackpill-f4.c index 402acd18af9..31563cf492b 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.c +++ b/src/platforms/common/blackpill-f4/blackpill-f4.c @@ -162,16 +162,16 @@ bool platform_nrst_get_val(void) static void adc_init(void) { rcc_periph_clock_enable(RCC_ADC1); - gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO0); + gpio_mode_setup(VTREF_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, VTREF_PIN); adc_power_off(ADC1); adc_disable_scan_mode(ADC1); - adc_set_sample_time(ADC1, ADC_CHANNEL0, ADC_SMPR_SMP_480CYC); + adc_set_sample_time(ADC1, VTREF_CHANNEL, ADC_SMPR_SMP_480CYC); adc_power_on(ADC1); } static uint16_t platform_adc_read(void) { - const uint8_t channel = ADC_CHANNEL0; + const uint8_t channel = VTREF_CHANNEL; adc_set_regular_sequence(ADC1, 1, &channel); adc_start_conversion_regular(ADC1); while (!adc_eoc(ADC1)) diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.h b/src/platforms/common/blackpill-f4/blackpill-f4.h index 3333b5ba5f2..1a18a4bbc6e 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.h +++ b/src/platforms/common/blackpill-f4/blackpill-f4.h @@ -196,6 +196,10 @@ extern bool debug_bmp; #define OB_SPI_CS_PORT GPIOA #define OB_SPI_CS GPIO4 +#define VTREF_PORT GPIOB +#define VTREF_PIN GPIO0 +#define VTREF_CHANNEL ADC_CHANNEL8 + /* USART2 with PA2 and PA3 is selected as USBUSART. Alternatively USART1 with PB6 and PB7 can be used. */ #define USBUSART USBUSART2 #define USBUSART_CR1 USBUSART2_CR1 From ef1650d284d9f3aed1a5813d8d7befc50581f3e8 Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sun, 10 Nov 2024 23:03:11 +0300 Subject: [PATCH 3/4] blackpill-f4: Implement Vrefint-based ADC correction --- src/platforms/common/blackpill-f4/blackpill-f4.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.c b/src/platforms/common/blackpill-f4/blackpill-f4.c index 31563cf492b..179b4785970 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.c +++ b/src/platforms/common/blackpill-f4/blackpill-f4.c @@ -165,19 +165,27 @@ static void adc_init(void) gpio_mode_setup(VTREF_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, VTREF_PIN); adc_power_off(ADC1); adc_disable_scan_mode(ADC1); + adc_set_resolution(ADC1, ADC_CR1_RES_12BIT); adc_set_sample_time(ADC1, VTREF_CHANNEL, ADC_SMPR_SMP_480CYC); + adc_set_sample_time(ADC1, ADC_CHANNEL_VREF, ADC_SMPR_SMP_480CYC); + adc_enable_temperature_sensor(); adc_power_on(ADC1); } static uint16_t platform_adc_read(void) { - const uint8_t channel = VTREF_CHANNEL; - adc_set_regular_sequence(ADC1, 1, &channel); + const uint8_t channels[] = {ADC_CHANNEL_VREF, VTREF_CHANNEL}; + adc_set_regular_sequence(ADC1, ARRAY_LENGTH(channels), channels); adc_start_conversion_regular(ADC1); while (!adc_eoc(ADC1)) continue; - uint32_t value = adc_read_regular(ADC1); - return value; + const uint16_t vrefint_sample = adc_read_regular(ADC1); + const uint16_t value = adc_read_regular(ADC1); + /* Vrefint = 1.21V typ, Vdda = 3.3V, expected code of 1501 */ + const uint16_t vrefint_expected = 1210U * 4095U / 3300U; + const uint16_t value_adj = value * vrefint_expected / vrefint_sample; + DEBUG_INFO("%s: Vrefint=%u, VTref=%u, returning %u", __func__, vrefint_sample, value, value_adj); + return value_adj; } const char *platform_target_voltage(void) From 9ab9c8efe5db4ba7bd6696ff9c759eb5ae22e907 Mon Sep 17 00:00:00 2001 From: ALTracer <11005378+ALTracer@users.noreply.github.com> Date: Sat, 26 Apr 2025 17:18:19 +0300 Subject: [PATCH 4/4] blackpill-f4: split adc conversions * Power-off ADC after use (only used upon target scan) * Prescale ADC1 clock (APB2) by 4 * Refactor regular sequence of 2 channels into two launches --- .../common/blackpill-f4/blackpill-f4.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/platforms/common/blackpill-f4/blackpill-f4.c b/src/platforms/common/blackpill-f4/blackpill-f4.c index 179b4785970..95f45907cce 100644 --- a/src/platforms/common/blackpill-f4/blackpill-f4.c +++ b/src/platforms/common/blackpill-f4/blackpill-f4.c @@ -164,27 +164,33 @@ static void adc_init(void) rcc_periph_clock_enable(RCC_ADC1); gpio_mode_setup(VTREF_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, VTREF_PIN); adc_power_off(ADC1); - adc_disable_scan_mode(ADC1); - adc_set_resolution(ADC1, ADC_CR1_RES_12BIT); + /* Pclk2=Hclk=96 MHz, use ADCclk=24 MHz to stay below 36 per datasheet. Then 480 cycles take 20us. */ + adc_set_clk_prescale(ADC_CCR_ADCPRE_BY4); adc_set_sample_time(ADC1, VTREF_CHANNEL, ADC_SMPR_SMP_480CYC); adc_set_sample_time(ADC1, ADC_CHANNEL_VREF, ADC_SMPR_SMP_480CYC); adc_enable_temperature_sensor(); - adc_power_on(ADC1); } static uint16_t platform_adc_read(void) { - const uint8_t channels[] = {ADC_CHANNEL_VREF, VTREF_CHANNEL}; - adc_set_regular_sequence(ADC1, ARRAY_LENGTH(channels), channels); + const uint8_t channel17 = ADC_CHANNEL_VREF; + const uint8_t channel_vtref = VTREF_CHANNEL; + adc_power_on(ADC1); + adc_set_regular_sequence(ADC1, 1, &channel17); adc_start_conversion_regular(ADC1); while (!adc_eoc(ADC1)) continue; const uint16_t vrefint_sample = adc_read_regular(ADC1); + adc_set_regular_sequence(ADC1, 1, &channel_vtref); + adc_start_conversion_regular(ADC1); + while (!adc_eoc(ADC1)) + continue; const uint16_t value = adc_read_regular(ADC1); /* Vrefint = 1.21V typ, Vdda = 3.3V, expected code of 1501 */ const uint16_t vrefint_expected = 1210U * 4095U / 3300U; const uint16_t value_adj = value * vrefint_expected / vrefint_sample; - DEBUG_INFO("%s: Vrefint=%u, VTref=%u, returning %u", __func__, vrefint_sample, value, value_adj); + DEBUG_INFO("%s: Vrefint=%u, VTref=%u, returning %u\n", __func__, vrefint_sample, value, value_adj); + adc_power_off(ADC1); return value_adj; }