10000 stm32/machine_adc: Fix and improve STM32H5 support. · micropython/micropython@72ef2e6 · GitHub
[go: up one dir, main page]

Skip to content

Commit 72ef2e6

Browse files
renestraubdpgeorge
authored andcommitted
stm32/machine_adc: Fix and improve STM32H5 support.
Changes are: - Run ADC on PCLK/16. - Verify and optimize timings (ADC_STAB_DELAY_US, ADC_SAMPLETIME_DEFAULT). - Add support for STM32H5 VBAT and COREVDD channels on ADC2. - Replace ADC constants in machine_adc_locals_dict_table. - Convert STM32 literal to channel numbers in adc_config_channel with corresponding STM32 LL library functions (__LL_ADC_IS_CHANNEL_INTERNAL(), __LL_ADC_CHANNEL_TO_DECIMAL_NB()). Reasoning for the second last point: the STM32 driver literals are uint32_t that don't work with MP_ROM_INT() which handles signed 31 bit integers only. Introduce enumerator machine_adc_internal_ch_t to define external channels (0..19), internal channels (256..) and the special channel VREF (0xffff). Values are converted to STM32 literals with adc_ll_channel() when required in adc_config_and_read_u16(). Signed-off-by: Rene Straub <rene@see5.ch>
1 parent 64d24fc commit 72ef2e6

File tree

1 file changed

+104
-26
lines changed

1 file changed

+104
-26
lines changed

ports/stm32/machine_adc.c

Lines changed: 104 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@
4848
#elif defined(STM32G4)
4949
#define ADC_STAB_DELAY_US (20)
5050
#elif defined(STM32H5)
51-
#define ADC_STAB_DELAY_US (1) // TODO: Check if this is enough
51+
// Stabilization delay = 1 conversion cycle
52+
// ADC clk = PDIV / 16 = 250 MHz / 16 = 15.625 MHz -> 64 ns -> select 1 us
53+
#define ADC_STAB_DELAY_US (1)
5254
#elif defined(STM32L4)
5355
#define ADC_STAB_DELAY_US (10)
5456
#elif defined(STM32WB)
@@ -61,9 +63,14 @@
6163
#elif defined(STM32F4) || defined(STM32F7)
6264
#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_15CYCLES
6365
#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_480CYCLES
64-
#elif defined(STM32G4) || defined(STM32H5)
66+
#elif defined(STM32G4)
6567
#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_12CYCLES_5
6668
#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_247CYCLES_5
69+
#elif defined(STM32H5)
70+
// Worst case sampling time: slow channel, 12 bits, 680 ohms -> 165 ns
71+
// ADC clk = PDIV / 16 = 250 MHz / 16 = 15.625 MHz -> 64 ns -> 2.57 cycles -> select 6.5 cycles
72+
#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_6CYCLES_5
73+
#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_247CYCLES_5
6774
#elif defined(STM32H7)
6875
#define ADC_SAMPLETIME_DEFAULT ADC_SAMPLETIME_8CYCLES_5
6976
#define ADC_SAMPLETIME_DEFAULT_INT ADC_SAMPLETIME_387CYCLES_5
@@ -81,8 +88,65 @@
8188
// Timeout for waiting for end-of-conversion
8289
#define ADC_EOC_TIMEOUT_MS (10)
8390

84-
// This is a synthesised channel representing the maximum ADC reading (useful to scale other channels)
85-
#define ADC_CHANNEL_VREF (0xffff)
91+
// Channel IDs for machine.ADC object
92+
typedef enum _machine_adc_internal_ch_t {
93+
// Regular external ADC inputs (0..19)
94+
MACHINE_ADC_EXT_CH_0 = 0,
95+
MACHINE_ADC_EXT_CH_19 = 19,
96+
97+
// Internal ADC channels (256..)
98+
MACHINE_ADC_INT_CH_VREFINT = 256,
99+
MACHINE_ADC_INT_CH_TEMPSENSOR,
100+
#if defined(ADC_CHANNEL_VBAT)
101+
MACHINE_ADC_INT_CH_VBAT,
102+
#endif
103+
#if defined(ADC_CHANNEL_VDDCORE)
104+
MACHINE_ADC_INT_CH_VDDCORE,
105+
#endif
106+
107+
// This is a synthesised channel representing the maximum ADC reading (useful to scale other channels)
108+
MACHINE_ADC_CH_VREF = 0xffff // 0xffff for backward compatibility
109+
} machine_adc_internal_ch_t;
110+
111+
// Convert machine_adc_internal_ch_t value to STM32 library ADC channel literal.
112+
// This function is required as literals are uint32_t types that don't map with MP_ROM_INT (31 bit signed).
113+
STATIC uint32_t adc_ll_channel(uint32_t channel_id) {
114+
uint32_t adc_ll_ch;
115+
switch (channel_id) {
116+
// external channels map 1:1
117+
case MACHINE_ADC_EXT_CH_0 ... MACHINE_ADC_EXT_CH_19:
118+
adc_ll_ch = channel_id;
119+
break;
120+
121+
// internal channels are converted to STM32 ADC defines
122+
case MACHINE_ADC_INT_CH_VREFINT:
123+
adc_ll_ch = ADC_CHANNEL_VREFINT;
124+
break;
125+
case MACHINE_ADC_INT_CH_TEMPSENSOR:
126+
#if defined(STM32G4)
127+
adc_ll_ch = ADC_CHANNEL_TEMPSENSOR_ADC1;
128+
#else
129+
adc_ll_ch = ADC_CHANNEL_TEMPSENSOR;
130+
#endif
131+
break;
132+
#if defined(ADC_CHANNEL_VBAT)
133+
case MACHINE_ADC_INT_CH_VBAT:
134+
adc_ll_ch = ADC_CHANNEL_VBAT;
135+
break;
136+
#endif
137+
#if defined(ADC_CHANNEL_VDDCORE)
138+
case MACHINE_ADC_INT_CH_VDDCORE:
139+
adc_ll_ch = ADC_CHANNEL_VDDCORE;
140+
break;
141+
#endif
142+
143+
// To save code memory for costly error handling, default to Vref for unknown channels
144+
default:
145+
adc_ll_ch = ADC_CHANNEL_VREFINT;
146+
break;
147+
};
148+
return adc_ll_ch;
149+
}
86150

87151
static inline void adc_stabilisation_delay_us(uint32_t us) {
88152
mp_hal_delay_us(us + 1);
@@ -150,9 +214,9 @@ void adc_config(ADC_TypeDef *adc, uint32_t bits) {
150214
adc->CFGR2 = 2 << ADC_CFGR2_CKMODE_Pos; // PCLK/4 (synchronous clock mode)
151215
#elif defined(STM32F4) || defined(STM32F7) || defined(STM32L4)
152216
ADCx_COMMON->CCR = 0; // ADCPR=PCLK/2
153-
#elif defined(STM32G4)
217+
#elif defined(STM32G4) || defined(STM32H5)
154218
ADC12_COMMON->CCR = 7 << ADC_CCR_PRESC_Pos; // PCLK/16 (asynchronous clock mode)
155-
#elif defined(STM32H5) || defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
219+
#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
156220
ADC12_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos;
157221
#elif defined(STM32H7)
158222
ADC12_COMMON->CCR = 3 << ADC_CCR_CKMODE_Pos;
@@ -352,9 +416,16 @@ STATIC void adc_config_channel(ADC_TypeDef *adc, uint32_t channel, uint32_t samp
352416
#else
353417
adc_common->CCR |= ADC_CCR_VBATEN;
354418
#endif
419+
#if defined(STM32H5)
420+
} else if (channel == ADC_CHANNEL_VDDCORE) {
421+
adc->OR |= ADC_OR_OP0; // Enable Vddcore channel on ADC2
422+
#endif
423+
}
424+
#if defined(STM32G4) || defined(STM32H5)
425+
// G4 and H5 use encoded literals for internal channels -> extract ADC channel for following code
426+
if (__LL_ADC_IS_CHANNEL_INTERNAL(channel)) {
427+
channel = __LL_ADC_CHANNEL_TO_DECIMAL_NB(channel);
355428
}
356-
#if defined(STM32G4)
357-
channel = __LL_ADC_CHANNEL_TO_DECIMAL_NB(channel);
358429
adc->DIFSEL &= ~(1 << channel); // Set channel to Single-ended.
359430
#endif
360431
adc->SQR1 = (channel & 0x1f) << ADC_SQR1_SQ1_Pos | (1 - 1) << ADC_SQR1_L_Pos;
@@ -391,10 +462,13 @@ STATIC uint32_t adc_read_channel(ADC_TypeDef *adc) {
391462
}
392463

393464
uint32_t adc_config_and_read_u16(ADC_TypeDef *adc, uint32_t channel, uint32_t sample_time) {
394-
if (channel == ADC_CHANNEL_VREF) {
465+
if (channel == MACHINE_ADC_CH_VREF) {
395466
return 0xffff;
396467
}
397468

469+
// Map internal channel_id to STM32 ADC driver value/literal.
470+
channel = adc_ll_channel(channel);
471+
398472
// Select, configure and read the channel.
399473
adc_config_channel(adc, channel, sample_time);
400474
uint32_t raw = adc_read_channel(adc);
@@ -421,7 +495,7 @@ const mp_obj_type_t machine_adc_type;
421495
typedef struct _machine_adc_obj_t {
422496
mp_obj_base_t base;
423497
ADC_TypeDef *adc;
424-
uint32_t channel;
498+
uint32_t channel; // one of machine_adc_internal_ch_t
425499
uint32_t sample_time;
426500
} machine_adc_obj_t;
427501

@@ -452,20 +526,25 @@ STATIC mp_obj_t machine_adc_make_new(const mp_obj_type_t *type, size_t n_args, s
452526
uint32_t sample_time = ADC_SAMPLETIME_DEFAULT;
453527
ADC_TypeDef *adc;
454528
if (mp_obj_is_int(source)) {
529+
channel = mp_obj_get_int(source);
455530
#if defined(STM32WL)
456531
adc = ADC;
532+
#elif defined(STM32H5)
533+
// on STM32H5 vbat and vddcore channels are on ADC2
534+
if (channel == MACHINE_ADC_INT_CH_VBAT || channel == MACHINE_ADC_INT_CH_VDDCORE) {
535+
adc = ADC2;
536+
} else {
537+
adc = ADC1;
538+
}
457539
#else
458540
adc = ADC1;
459541
#endif
460-
channel = mp_obj_get_int(source);
461-
if (channel == ADC_CHANNEL_VREFINT
462-
#if defined(STM32G4)
463-
|| channel == ADC_CHANNEL_TEMPSENSOR_ADC1
464-
#else
465-
|| channel == ADC_CHANNEL_TEMPSENSOR
466-
#endif
542+
if (channel == MACHINE_ADC_INT_CH_VREFINT || channel == MACHINE_ADC_INT_CH_TEMPSENSOR
467543
#if defined(ADC_CHANNEL_VBAT)
468-
|| channel == ADC_CHANNEL_VBAT
544+
|| channel == MACHINE_ADC_INT_CH_VBAT
545+
#endif
546+
#if defined(ADC_CHANNEL_VDDCORE)
547+
|| channel == MACHINE_ADC_INT_CH_VDDCORE
469548
#endif
470549
) {
471550
sample_time = ADC_SAMPLETIME_DEFAULT_INT;
@@ -516,15 +595,14 @@ MP_DEFINE_CONST_FUN_OBJ_1(machine_adc_read_u16_obj, machine_adc_read_u16);
516595
STATIC const mp_rom_map_elem_t machine_adc_locals_dict_table[] = {
517596
{ MP_ROM_QSTR(MP_QSTR_read_u16), MP_ROM_PTR(&machine_adc_read_u16_obj) },
518597

519-
{ MP_ROM_QSTR(MP_QSTR_VREF), MP_ROM_INT(ADC_CHANNEL_VREF) },
520-
{ MP_ROM_QSTR(MP_QSTR_CORE_VREF), MP_ROM_INT(ADC_CHANNEL_VREFINT) },
521-
#if defined(STM32G4)
522-
{ MP_ROM_QSTR(MP_QSTR_CORE_TEMP), MP_ROM_INT(ADC_CHANNEL_TEMPSENSOR_ADC1) },
523-
#else
524-
{ MP_ROM_QSTR(MP_QSTR_CORE_TEMP), MP_ROM_INT(ADC_CHANNEL_TEMPSENSOR) },
525-
#endif
598+
{ MP_ROM_QSTR(MP_QSTR_VREF), MP_ROM_INT(MACHINE_ADC_CH_VREF) },
599+
{ MP_ROM_QSTR(MP_QSTR_CORE_VREF), MP_ROM_INT(MACHINE_ADC_INT_CH_VREFINT) },
600+
{ MP_ROM_QSTR(MP_QSTR_CORE_TEMP), MP_ROM_INT(MACHINE_ADC_INT_CH_TEMPSENSOR) },
526601
#if defined(ADC_CHANNEL_VBAT)
527-
{ MP_ROM_QSTR(MP_QSTR_CORE_VBAT), MP_ROM_INT(ADC_CHANNEL_VBAT) },
602+
{ MP_ROM_QSTR(MP_QSTR_CORE_VBAT), MP_ROM_INT(MACHINE_ADC_INT_CH_VBAT) },
603+
#endif
604+
#if defined(ADC_CHANNEL_VDDCORE)
605+
{ MP_ROM_QSTR(MP_QSTR_CORE_VDD), MP_ROM_INT(MACHINE_ADC_INT_CH_VDDCORE) },
528606
#endif
529607
};
530608
STATIC MP_DEFINE_CONST_DICT(machine_adc_locals_dict, machine_adc_locals_dict_table);

0 commit comments

Comments
 (0)
0