samples: boards: stm32 mco output control

This sample enables and configures the MCO1/2 output
for stm32 target boards.
MCO_PRE_DIV_n is defined by the stm32XX_clock.h

Signed-off-by: Francois Ramu <francois.ramu@st.com>
This commit is contained in:
Francois Ramu 2024-11-15 15:48:39 +01:00 committed by Anas Nashif
commit 17fcb33eae
7 changed files with 86 additions and 24 deletions

View file

@ -16,6 +16,13 @@ Requirements
The SoC should support MCO functionality and use a pin that has the MCO alternate function.
To support another board, add a dts overlay file in boards folder.
Make sure that the output clock is enabled in dts overlay file.
Depending on the stm32 serie, several clock source and prescaler are possible for each MCOx.
The clock source is set by the DTS among the possible values for each stm32 serie.
The prescaler is set by the DTS, through the property ``prescaler = <MCOx_PRE(MCO_PRE_DIV_n)>;``
See :zephyr_file:`dts/bindings/clock/st,stm32-clock-mco.yaml`
It is required to check the Reference Manual to configure the DTS correctly.
Building and Running

View file

@ -0,0 +1,30 @@
/* Enable the PLLI2s and set it as clock source for the MCO2 (with prescaler 5) */
&plli2s {
div-m = <8>;
mul-n = <100>;
div-r = <2>;
clocks = <&clk_hse>;
status = "okay";
};
/* see RefMan RM0383 */
&mco1 {
/* Select One of the line below for clock source */
clocks = <&rcc STM32_SRC_HSI MCO1_SEL(0)>;
/* clocks = <&rcc STM32_SRC_LSE MCO1_SEL(1)>; */
/* clocks = <&rcc STM32_SRC_HSE MCO1_SEL(2)>; */
/* clocks = <&rcc STM32_SRC_PLL_P MCO1_SEL(3)>; */
prescaler = <MCO1_PRE(MCO_PRE_DIV_2)>;
pinctrl-0 = <&rcc_mco_1_pa8>;
pinctrl-names = "default";
status = "okay";
};
&mco2 {
clocks = <&rcc STM32_SRC_PLLI2S_R MCO2_SEL(1)>;
prescaler = <MCO2_PRE(MCO_PRE_DIV_5)>;
pinctrl-0 = <&rcc_mco_2_pc9>;
pinctrl-names = "default";
status = "okay";
};

View file

@ -0,0 +1,30 @@
/* Enable the PLLI2s and set it as clock source for the MCO2 (with prescaler 2) : 25MHz */
&plli2s {
div-m = <8>;
mul-n = <100>;
div-r = <2>;
clocks = <&clk_hse>;
status = "okay";
};
/* see RefMan RM0390 */
&mco1 {
/* Select One of the line below for clock source */
/* clocks = <&rcc STM32_SRC_HSI MCO1_SEL(0)>; */
/* clocks = <&rcc STM32_SRC_LSE MCO1_SEL(1)>; */
clocks = <&rcc STM32_SRC_HSE MCO1_SEL(2)>;
/* clocks = <&rcc STM32_SRC_PLL_P MCO1_SEL(3)>;*/
prescaler = <MCO1_PRE(MCO_PRE_DIV_1)>;
pinctrl-0 = <&rcc_mco_1_pa8>;
pinctrl-names = "default";
status = "okay";
};
&mco2 {
clocks = <&rcc STM32_SRC_PLLI2S_R MCO2_SEL(1)>;
prescaler = <MCO2_PRE(MCO_PRE_DIV_2)>;
pinctrl-0 = <&rcc_mco_2_pc9>;
pinctrl-names = "default";
status = "okay";
};

View file

@ -8,15 +8,10 @@
*/
#define MCO1_SEL_LSE 7
/* See reference manual (RM0456):
* 0b001: MCO divided by 2
*/
#define MCO1_PRE_DIV_2 1
&mco1 {
status = "okay";
clocks = <&rcc STM32_SRC_LSE MCO1_SEL(MCO1_SEL_LSE)>;
prescaler = <MCO1_PRE(MCO1_PRE_DIV_2)>;
prescaler = <MCO1_PRE(MCO_PRE_DIV_2)>;
pinctrl-0 = <&rcc_mco_pa8>;
pinctrl-names = "default";
};

View file

@ -12,15 +12,10 @@
*/
#define MCO1_SEL_LSE 1
/* See reference manual (RM0385):
* 0b100: division by 2
*/
#define MCO1_PRE_DIV_2 4
&mco1 {
status = "okay";
clocks = <&rcc STM32_SRC_LSE MCO1_SEL(MCO1_SEL_LSE)>;
prescaler = <MCO1_PRE(MCO1_PRE_DIV_2)>;
prescaler = <MCO1_PRE(MCO_PRE_DIV_2)>;
pinctrl-0 = <&rcc_mco_1_pa8>; /* D10 (CN7) */
pinctrl-names = "default";
};
@ -30,15 +25,10 @@
*/
#define MCO2_SEL_HSE 2
/* See reference manual (RM0385):
* 0b111: division by 5
*/
#define MCO2_PRE_DIV_5 7
&mco2 {
status = "okay";
clocks = <&rcc STM32_SRC_HSE MCO2_SEL(MCO2_SEL_HSE)>;
prescaler = <MCO2_PRE(MCO2_PRE_DIV_5)>;
prescaler = <MCO2_PRE(MCO_PRE_DIV_5)>;
pinctrl-0 = <&rcc_mco_2_pc9>; /* uSD_D1 (CN3 pin 8) */
pinctrl-names = "default";
};

View file

@ -3,6 +3,10 @@ sample:
tests:
sample.board.stm32.mco:
platform_allow:
- nucleo_f411re
- nucleo_f446ze
- stm32f746g_disco
- nucleo_u5a5zj_q
integration_platforms:
- stm32f746g_disco
tags: board

View file

@ -9,7 +9,6 @@
int main(void)
{
const struct device *dev;
/* This sample demonstrates MCO usage via Device Tree.
* MCO configuration is performed in the Device Tree overlay files.
@ -17,23 +16,30 @@ int main(void)
* initialization. This sample checks that all MCOs are ready - if so,
* the selected clock should be visible on the chosen GPIO pin.
*/
dev = DEVICE_DT_GET(DT_NODELABEL(mco1));
if (device_is_ready(dev)) {
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(mco1))
const struct device *dev1;
dev1 = DEVICE_DT_GET(DT_NODELABEL(mco1));
if (device_is_ready(dev1)) {
printk("MCO1 device successfully configured\n");
} else {
printk("MCO1 device not ready\n");
return -1;
}
#endif /* mco1 */
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(mco2))
dev = DEVICE_DT_GET(DT_NODELABEL(mco2));
if (device_is_ready(dev)) {
const struct device *dev2;
dev2 = DEVICE_DT_GET(DT_NODELABEL(mco2));
if (device_is_ready(dev2)) {
printk("MCO2 device successfully configured\n");
} else {
printk("MCO2 device not ready\n");
return -1;
}
#endif
#endif /* mco2 */
printk("\nDisplayed the status of all MCO devices - end of example.\n");
return 0;