Skip to content

Conversation

@gautierg-st
Copy link
Contributor

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, the clock-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.

Copy link
Contributor

@mathieuchopstm mathieuchopstm left a 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.

Comment on lines +1981 to +1966
.pclken = {.bus = DT_INST_CLOCKS_CELL_BY_NAME(index, adcx, bus), \
.enr = DT_INST_CLOCKS_CELL_BY_NAME(index, adcx, bits)}, \
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My 2 cents. div is not left uninitialized, It's 0 which is fine if division is not used (as per the various stm32_clock_control_get_subsys_rate() implemenations), no?
That said, I agree using an STM32 helper macro for these would be worth it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My 2 cents. div is not left uninitialized, It's 0

By uninitialized, I meant that it doesn't take its value from DT 🙂

(.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,)) \
Copy link
Contributor

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.

Copy link
Contributor

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:

  1. commit title is not very intuitive. prefer the simpler rework STM32_DT_CLOCK_SELECT details?
  2. Since we're breaking STM32_DT_CLOCK_SELECT, I would suggest the new prototype to be instead STM32_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.

Copy link
Contributor Author

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).

Copy link
Contributor

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)

Copy link
Contributor Author

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 ?

Copy link
Member

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 ?

Copy link
Contributor

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.

Copy link
Contributor

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:

image

==> ((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 🤔

/**
* @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))))

Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The macro now uses MSB and LSB, all clock fields have been updated. Hopefully without error.

@gautierg-st
Copy link
Contributor Author

Rebased to fix conflicts, and comments taken into account.

Copy link
Contributor

@mathieuchopstm mathieuchopstm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do a second pass to make sure no selector has been broken but otherwise LGTM, minus a few points

@mathieuchopstm mathieuchopstm linked an issue Oct 22, 2025 that may be closed by this pull request
@mathieuchopstm mathieuchopstm added this to the future milestone Oct 22, 2025
@gautierg-st
Copy link
Contributor Author

LGTM but you need to rebase your series.

Thanks, done.

@erwango
Copy link
Member

erwango commented Oct 24, 2025

@kylebonnici Seems linter is wrong here: https://github.com/zephyrproject-rtos/zephyr/actions/runs/18772147196/job/53558655897?pr=97725#step:13:176:. It reports failure and proposes the following:

 			dmas = <&gpdma1 0 7 (STM32_DMA_PERIPH_TX | STM32_DMA_16BITS |
-					     STM32_DMA_PRIORITY_HIGH)>,
+				STM32_DMA_PRIORITY_HIGH)>,
 			       <&gpdma1 1 6 (STM32_DMA_PERIPH_RX | STM32_DMA_16BI

@gautierg-st
Copy link
Contributor Author

@kylebonnici Seems linter is wrong here: https://github.com/zephyrproject-rtos/zephyr/actions/runs/18772147196/job/53558655897?pr=97725#step:13:176:. It reports failure and proposes the following:

 			dmas = <&gpdma1 0 7 (STM32_DMA_PERIPH_TX | STM32_DMA_16BITS |
-					     STM32_DMA_PRIORITY_HIGH)>,
+				STM32_DMA_PRIORITY_HIGH)>,
 			       <&gpdma1 1 6 (STM32_DMA_PERIPH_RX | STM32_DMA_16BI

I've fixed the other issues reported by linter, but I'm waiting for feedback on this one.

@erwango erwango modified the milestones: future, v4.3.0 Oct 24, 2025
@kylebonnici
Copy link
Contributor

@gautierg-st

@kylebonnici Seems linter is wrong here: https://github.com/zephyrproject-rtos/zephyr/actions/runs/18772147196/job/53558655897?pr=97725#step:13:176:. It reports failure and proposes the following:

 			dmas = <&gpdma1 0 7 (STM32_DMA_PERIPH_TX | STM32_DMA_16BITS |
-					     STM32_DMA_PRIORITY_HIGH)>,
+				STM32_DMA_PRIORITY_HIGH)>,
 			       <&gpdma1 1 6 (STM32_DMA_PERIPH_RX | STM32_DMA_16BI

I've fixed the other issues reported by linter, but I'm waiting for feedback on this one.

is question s why it is aligning STM32_DMA_PRIORITY_HIGH with dmas = < and not dmas = <&gpdma1 0 7 (?

@gautierg-st
Copy link
Contributor Author

is question s why it is aligning STM32_DMA_PRIORITY_HIGH with dmas = < and not dmas = <&gpdma1 0 7 (?

Yes, that's the question.

Copy link
Contributor

@mathieuchopstm mathieuchopstm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise LGTM

Reworks the way the STM32_DT_CLOCK_SELECT builds its elements. Instead of
taking a mask, it takes the MSB of the field. From the MSB and LSB, we
calculate the width of the field, and this width is then stored (instead
of the mask). 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.

This also fixes a few issues like STM32H7 MCO macros, and adds MCO_PRE for
STM32N6.

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]>
@gautierg-st
Copy link
Contributor Author

I've fixed the linter warnings since I'd like this PR to be merged for v4.3.

Fix formatting errors reported by the dts linter.

Signed-off-by: Guillaume Gautier <[email protected]>
@kylebonnici
Copy link
Contributor

kylebonnici commented Oct 24, 2025

is question s why it is aligning STM32_DMA_PRIORITY_HIGH with dmas = < and not dmas = <&gpdma1 0 7 (?

Yes, that's the question.

This was discussed here:

TLDR;

the linter will always format with dmas = < and will not take the expression group level into consideration yet but open to have a discussion on this!

Solution for your use case.
Move the whole expression down...

 			dmas = <&gpdma1 0 7
-					     STM32_DMA_PRIORITY_HIGH)>,
+				(STM32_DMA_PERIPH_TX | STM32_DMA_16BITS | STM32_DMA_PRIORITY_HIGH)>,
 			       <&gpdma1 1 6 (STM32_DMA_PERIPH_RX | STM32_DMA_16BI

in some cases this may still be too long ....

in such case consider

 			dmas = <&gpdma1 0 7
-					     STM32_DMA_PRIORITY_HIGH)>,
+				(STM32_DMA_PERIPH_TX | STM32_DMA_16BITS |
+				STM32_DMA_PRIORITY_HIGH)>,
 			       <&gpdma1 1 6 (STM32_DMA_PERIPH_RX | STM32_DMA_16BI

Do post an issue on the linter repo and a suggestion and I am happy to consider adding this. FYI this will come into play when we add auto splitting lines that exceed 100 chars. In such a case the linter would opt to move the whole groups to a new line to reduce need to split line again.

@sonarqubecloud
Copy link

@erwango erwango assigned erwango and unassigned nordic-krch Oct 24, 2025
@cfriedt cfriedt merged commit b18a70e into zephyrproject-rtos:main Oct 24, 2025
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ADC Analog-to-Digital Converter (ADC) area: Boards/SoCs area: Clock Control area: Devicetree Bindings area: Tests Issues related to a particular existing or missing test platform: STM32 ST Micro STM32 Release Notes To be mentioned in the release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

STM32H7 MCO select and prescaler masks are incorrect

8 participants