-
Notifications
You must be signed in to change notification settings - Fork 8.1k
STM32 ADC: support prescaler from RCC #97725
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Reworks the way the STM32_DT_CLOCK_SELECT builds its elements. Instead of defining a mask, we define a width which is the number of bits of the register field. This allows to gain space for higher values for the fields. This larger space is necessary to add the selection of the ADC prescaler on STM32N6 because it is an 8-bit long field. The allowed width is from 1 to 8 (and internally stored as 0-7 to fit on 3 bits). STM32_DT_CLKSEL_MASK_GET keeps the same name, since we still need the mask, and returns the bitmask from the width with the BIT_MASK macro. Other STM32_DT_CLKSEL_MASK_* macros are renamed with WIDTH. All call to STM32_DT_CLOCK_SELECT are updated to reflect the change and use a width instead of a mask. Signed-off-by: Guillaume Gautier <[email protected]>
…and u3 This commit adds the RCC configurations for ADC prescaler for STM32F1, F3, N6 and U3. Signed-off-by: Guillaume Gautier <[email protected]>
To easily differentiate between the different clocks that can be configured in device tree, make their naming mandatory, and explicit what the expected names are. Add these names in all dtsi and dts files that need them. Signed-off-by: Guillaume Gautier <[email protected]>
Some series like F1, F3, N6 and U3 use an ADC prescaler defined in the RCC. Instead of adding specific properties in the RCC driver, use the secondary clock system to configure the prescaler. The ADC driver now configures the clocks depending on their presence and their name. Three clocks can be defined: - the register clock (mandatory for all series) - the kernel clock (depends on series) - the prescaler value (depends on series) Signed-off-by: Guillaume Gautier <[email protected]>
Now that the ADC prescaler are set within the driver using the clock system, the specific rcc compatibles for F1 and F3 are no longer useful. Replace them with the standard one (from which they were derived). Signed-off-by: Guillaume Gautier <[email protected]>
Now that the ADC prescaler are set within the driver using the clock system, remove the specific setting of the prescaler from the clock driver. Signed-off-by: Guillaume Gautier <[email protected]>
Update STM32 ADC binding description now that the STM32F3 ADC asynchronous prescaler is set through the clock property. Signed-off-by: Guillaume Gautier <[email protected]>
Update the 4.3 migration guide to include the change made on the STM32 ADC clocks. Signed-off-by: Guillaume Gautier <[email protected]>
0a4bf0d
to
261b108
Compare
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the STM32_DT_CLOCK_SELECT
update should be done in a separate PR. Not too blocking for me though.
} | ||
|
||
if (config->has_pclken_pre) { | ||
/* Set ADC RCC prescaler */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
/* Set ADC RCC prescaler */ | |
/* Configure ADC prescaler (at RCC level) */ |
.pclken = {.bus = DT_INST_CLOCKS_CELL_BY_NAME(index, adcx, bus), \ | ||
.enr = DT_INST_CLOCKS_CELL_BY_NAME(index, adcx, bits)}, \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I would make a STM32-level macro for this. Basically all drivers are "wrong" today (div
field left uninitialized) because they don't use the shared macro.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a change for another PR. As you say, all drivers are impacted, so I'm not going to introduce such a change in this one. There are enough as it is.
(.pclken_ker = {.bus = DT_INST_CLOCKS_CELL_BY_NAME(index, adc_ker, bus), \ | ||
.enr = DT_INST_CLOCKS_CELL_BY_NAME(index, adc_ker, bits)}, \ | ||
.has_pclken_ker = true,), \ | ||
(.has_pclken_ker = false,)) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: could be IF_ENABLED()
and leave has_pclken_ker
not initialized => default to false.
But I don't mind the extra verbosity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nits on commit include: zephyr: dt-bindings: clock: stm32: use width instead of bitmask
:
- commit title is not very intuitive. prefer the simpler
rework STM32_DT_CLOCK_SELECT details
? - Since we're breaking
STM32_DT_CLOCK_SELECT
, I would suggest the new prototype to be insteadSTM32_DT_CLOCK_SELECT(val, high_bit, low_bit, reg)
[1] low_bit
is merely a rename; high_bit
would be the bitfield's MSB index - width
would be computed internally as (high_bit - low_bit + 1)
. When copying RefMan, this would avoid the hurdle of computing bitfield width.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok with changing the commit title, but disagree with your prototype proposition. The rework was needed to gain space, make the macro more compact so that N6 prescaler could fit into it. Width is only 3-bit long, using another bit_pos would be 5-bit long. Reg would have to be reduced (not currently blocking since no reg are that long, but still, it could be needed one day).
Besides, I don't think it's a hurdle to "calculate" the width of the bitfield from RefMan (most are under 4-bit long, that's pretty easy to read).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok with changing the commit title, but disagree with your prototype proposition. The rework was needed to gain space, make the macro more compact so that N6 prescaler could fit into it. Width is only 3-bit long, using another bit_pos would be 5-bit long. Reg would have to be reduced (not currently blocking since no reg are that long, but still, it could be needed one day).
I am not suggesting to change the storage format but merely how the macro accepts parameters. When I said:
width
would be computed internally as(high_bit - low_bit + 1)
I meant that it would be computed internally as part of the macro (storage format is unchanged and contains width
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, ok, my bad, I misunderstood your proposition.
I don't have strong opinions on either choice, but I'll wait for other opinions before making any potential changes. @etienne-lms, @erwango ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the benefit of high_bit, low_bit
? Readability ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think having the lowest and highest bit position as macro argument make sense, but I'm quite used the GENMASK()
like macros. No strong opinion here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the benefit of
high_bit, low_bit
? Readability ?
Basically yes. Gives the information directly from reading RefMan:

==> ((val), 31, 30, CCIPR)
instead of having to derive size (as @gautierg-st said, it is often 1/2 bits so not too much of a hurdle, but still more error-prone than copy-paste from RM, and we're starting to see more and more "large" fields)
I think having the lowest and highest bit position as macro argument make sense, but I'm quite used the
GENMASK()
like macros. No strong opinion here.
GENMASK()
takes a high/low argument as well so I don't understand your point 🤔
zephyr/include/zephyr/sys/util.h
Lines 76 to 80 in 169fd6a
/** | |
* @brief Create a contiguous bitmask starting at bit position @p l | |
* and ending at position @p h. | |
*/ | |
#define GENMASK(h, l) (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GENMASK() takes a high/low argument as well so I don't understand your point 🤔
I meant I'm fine with such API but there maybe other point of view hence no strong opinion of mine on which of high-bit/low-bit or bit-offset/bit-size couple is to be preferred as argument.
/* ADCxx prescaler for all F3 but F37x: division factor */ | ||
#define ADCxx_PRE_DISABLED 0x0 | ||
#define ADCxx_PRE_DIV_1 0x10 | ||
#define ADCxx_PRE_DIV_2 0x11 | ||
#define ADCxx_PRE_DIV_4 0x12 | ||
#define ADCxx_PRE_DIV_6 0x13 | ||
#define ADCxx_PRE_DIV_8 0x14 | ||
#define ADCxx_PRE_DIV_10 0x15 | ||
#define ADCxx_PRE_DIV_12 0x16 | ||
#define ADCxx_PRE_DIV_16 0x17 | ||
#define ADCxx_PRE_DIV_32 0x18 | ||
#define ADCxx_PRE_DIV_64 0x19 | ||
#define ADCxx_PRE_DIV_128 0x1A | ||
#define ADCxx_PRE_DIV_256 0x1B | ||
|
||
/* ADC prescaler for F37x: division factor */ | ||
#define ADC_PRE_DIV_2 0 | ||
#define ADC_PRE_DIV_4 1 | ||
#define ADC_PRE_DIV_6 2 | ||
#define ADC_PRE_DIV_8 3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a separate stm32f37x_clock.h
(as done for other series) should be introduced. This would allow for more consistency across series.
The definitions in this file can be gated behind a symbol that only it defines such that it overrides them cleanly, i.e.:
+#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_STM32F37X_CLOCK_H_
+ /* STM32F37x has specific ADC prescaler definitions */
...
Expected names are the following: | ||
- "adcx" for the enabling the register clock (mandatory) | ||
- "adc_ker" for configuring the kernel clock (if applicable) | ||
- "adc_pre" for configuring the prescaler (if applicable) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be mentioned somewhere that one prescaler may be shared by several ADCs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's also the case for the kernel clock (at least sometimes, and it can even be shared with DAC), so it should be mentioned too.
#define MCO1_SEL(val) STM32_DT_CLOCK_SELECT((val), 3, 24, CFGR1_REG) | ||
/* No MCO prescaler support on STM32F1 series. */ | ||
|
||
/* ADC prescaler : division factor */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/* ADC prescaler : division factor */ | |
/* ADC prescaler: division factor */ |
But IDK if columns are very useful here?
/* ADC prescaler : division factor */ | |
/* ADC prescaler division factor */ |
ditto all
On STM32F3x (except STM32F37x), this configures only the synchronous | ||
prescaler (see properties adcXX-prescaler in st,stm32f3-rcc bindings to | ||
set asynchronous prescaler). | ||
prescaler (use the clock property to set asynchronous prescaler). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The STM32F37x also have a clock property for ADC_PRE
, so isn't this incorrect? Or are both prescalers applied in that instance? The comment could use some additional clarification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
STM32F37x has the same ADC as STM32F1 and uses the "stm32f1-adc" compatible which removes this property and the "st,adc-clock-source" property since they are not applicable for them.
So maybe "(except STM32F37x)" is not even worth mentioning since it doesn't use this compatible anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is what I would have suggested. (removing (except STM32F37x)
)
The goal of this PR is to add the support of the ADC prescaler located in RCC for some series (F1, F3, N6, U3).
Though already supported in F1 and F3, it was through a specific property of the RCC. To avoid increasing the complexity on this end, the prescaler is configured the same way as for a kernel clock, in the ADC
clocks
property in device tree.This allows to remove the RCC specificities of F1 and F3.
This led to changes in the STM32 clock defines due to the fact that the N6 prescaler register field is 8-bit long, so the macros needed to be reworked to make it fit.
Lastly, since we can now have up to three different clocks in the
clocks
properties, instead of relying on ordering, theclock-names
property is mandatory for all ADC instances. Names have been added in existing dtsi, dts and overlay files, but it shall be redefined if a clock source or a prescaler is added.