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
Add driver support for ADC1 of stm32 #13447
Conversation
All checks are passing now. Review history of this comment for details about previous failed status. |
To test this code, we should enable adc driver in menuconfig and add pinmux config in board specific file.
Test application code is
|
Hi @erwango , I'v only tested this code on f4 board, could you test it on other boards that available for you when you got some time? |
Generic DMA driver of stm32 is under development in #13364 , without DMA support many stm32s won't be able to catch up EOC interrupts generated by channels conversion, this will cause overrun error and lost data. So Only one channel can be put in one adc sequence in this driver. |
I was interested in the ADC driver for STM32. west init zephyrproject -m https://github.com/KwonTae-young/zephyr/ --mr adc_stm32-new_stm32f4-disco
cd zephyrproject/zephyr
source zephyr-env.sh
mkdir samples/basic/adc/build
cd samples/basic/adc/build
cmake -DBOARD=stm32f4_disco ..
make -j8 flash ADC works well.
|
@KwonTae-young Thanks for your interest. 😁 |
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.
Initial feedback
drivers/adc/adc_stm32_v2.c
Outdated
|
||
void adc_stm32_init_soc(ADC_TypeDef *adc) | ||
{ | ||
adc->CR2 |= ADC_CR2_ADON; |
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.
Why not using LL_ADC_Enable
and factorize this part?
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.
LL_ADC_Enable can be applied here, but I was thinking if I used LL lib somewhere, it's better to use LL lib everywhere. We talked about why I do not think LL lib is good for this generic driver, and except this function, some functions like getting EOC flags from registers uses different functions between different series of stm32 in LL lib.
So should I use LL and direct register access in the same driver?
I personally prefer to use direct register access for all operations.
This PR should be only merged after #13501 is merged. |
drivers/adc/adc_stm32.c
Outdated
|
||
adc_context_start_read(&data->ctx, sequence); | ||
err = adc_context_wait_for_completion(&data->ctx); | ||
adc_context_release(&data->ctx, err); |
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.
Remove this line. The lock is now released in adc_stm32_read[_sync]
.
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.
Right.
Updated to use LL lib. |
@@ -131,6 +131,7 @@ | |||
/dts/arm/st/ @erwango | |||
/dts/arm/nordic/ @ioannisg @carlescufi | |||
/dts/bindings/can @alexanderwachter | |||
/dts/bindings/iio/adc/st,stm32-adc.yaml @cybertale |
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.
Please also add drivers/adc/adc_stm32.c
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
@cybertale , since your work is close to mature and complete, could you update the description of the commit with a description of the work and the way it was tested? (this could edited later on with further addition) |
@erwango Sure! |
#define ADC_GAIN ADC_GAIN_1 | ||
#define ADC_REFERENCE ADC_REF_INTERNAL | ||
#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT | ||
#define ADC_1ST_CHANNEL_ID 0 |
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.
These parameters are exactly the same as the ones for NUCLEO_F091RC
. Wouldn't it be better to use:
#elif defined(CONFIG_BOARD_NUCLEO_F091RC) || \
defined(CONFIG_BOARD_NUCLEO_F103RB)
Same applies to a couple of Nucleo boards using 10-bit resolution.
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.
Yes, that's better
#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT | ||
#define ADC_1ST_CHANNEL_ID 0 | ||
|
||
#elif defined(CONFIG_BOARD_NUCLEO_F103RB) |
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.
Duplicate entry.
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.
+1 for doc changes
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 promising, some more comments
drivers/adc/Kconfig.stm32
Outdated
bool "STM32 ADC driver" | ||
depends on SOC_FAMILY_STM32 | ||
help | ||
Enable the driver implementation for the stm32xx ADC |
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.
Use two spaces alignment difference between "help" and help paragrah.
drivers/adc/adc_stm32.c
Outdated
|
||
adc_context_on_sampling_done(&data->ctx, dev); | ||
|
||
LOG_INF("ISR triggered."); |
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.
Change to LOG_DBG
drivers/adc/adc_stm32.c
Outdated
adc_stm32_setup_speed(dev, channel_cfg->channel_id, | ||
acq_time_index); | ||
|
||
LOG_INF("Channel setup succeeded!"); |
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.
LOG_DBG
default y | ||
help | ||
Enable ADC1 | ||
|
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.
Miss ADC_2 and _3, since available in the driver
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'm actually thinking about removing them, because there are so many different product lines, and different amount of ADCs they have, and also some ADCs share interrupt vector, so there should be some code for identifying which instance calls the interrupt. I would like another PR to do these things because this PR can be merged so users of STM32 can have basic ADC support.
But I'm worrying what Geo said about the merge window, but I see zephyr's doc says
As a general rule, if you miss the merge window for a given feature, the best thing to do is to wait for the next development cycle. (An occasional exception is made for drivers for previously unsupported hardware; if they do not touch any other in-tree code, they cannot cause regressions and should be safe to add at any time).
So if this passes all tests and clean, we should be able to merge this PR soon, right?
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 up to @galak to settle on this. Though, I'm not quite in favor of it. Even it could not be a source of regression, it could be a source of bugs, and branch maturity is tightly controlled.
Besides, there are several PR that could pretend be merged as this PR (L1/G0/WB). There is no reason this one is privileged.
So I think the paragraph you mention should actually be corrected.
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.
Understand, so I'll just wait. ;)
It seems like the Shippable tests failed because another work is under going, #14242 should be able to solve the problem. |
@@ -41,6 +41,8 @@ static const struct pin_config pinconf[] = { | |||
{STM32_PIN_PB14, STM32F4_PINMUX_FUNC_PB14_SPI2_MISO}, | |||
{STM32_PIN_PB15, STM32F4_PINMUX_FUNC_PB15_SPI2_MOSI}, | |||
#endif /* CONFIG_SPI_1 */ | |||
#ifdef CONFIG_ADC_1 | |||
#endif /* CONFIG_ADC_1 */ |
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.
Is this empty #ifdef
block intentional?
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.
Sorry, my mistake
@cybertale, tested on L452 SoC, works great. |
drivers/adc/adc_stm32.c
Outdated
LL_ADC_EnableInternalRegulator(adc); | ||
u32_t wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US / 10UL) * | ||
(SystemCoreClock / (100000UL * 2UL))); | ||
while (wait_loop_index != 0UL) { |
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.
k_busy_wait(LL_ADC_DELAY_INTERNAL_REGUL_STAB_US);
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's better.
btw, I've added support for the STM32G0 in this branch: https://github.com/shphilippe/zephyr/tree/stm32g070-adc |
I see G0 support is not in plan of milestone v1.15, right? So you can feel free to push support for ADC of G0 after this. Or what's your plan? :) |
I don't have much plans. Just trying to contribute back code which can be open sourced :) |
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.
Mostly nitpicks
return -EIO; | ||
} | ||
|
||
#if defined(CONFIG_SOC_SERIES_STM32L4X) |
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 feel some more comments in this init function would be welcome
drivers/adc/adc_stm32.c
Outdated
#if defined(CONFIG_SOC_SERIES_STM32F0X) || \ | ||
defined(CONFIG_SOC_SERIES_STM32L0X) | ||
LL_ADC_SetClock(adc, LL_ADC_CLOCK_SYNC_PCLK_DIV4); | ||
#endif |
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.
Why not using elif there?
drivers/adc/adc_stm32.c
Outdated
#endif | ||
LL_ADC_Enable(adc); | ||
#ifdef CONFIG_SOC_SERIES_STM32L4X | ||
/* Refer to the description of ADRDY in reference manual. */ |
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.
"Refer to reference manual" applies to the while code I guess.
A plain comment would be nice.
|
||
LL_ADC_SetCommonPathInternalCh(ADC, LL_ADC_PATH_INTERNAL_VREFINT); | ||
#endif | ||
LL_ADC_Enable(adc); |
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.
Break lines around this.
|
||
if (sequence->options) { | ||
needed_buffer_size *= (1 + sequence->options->extra_samplings); | ||
} |
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.
Break a line here
LOG_ERR("Provided buffer is too small (%u/%u)", | ||
sequence->buffer_size, needed_buffer_size); | ||
return -ENOMEM; | ||
} |
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.
Same here
LL_ADC_EnableIT_EOCS(adc); | ||
#endif | ||
|
||
adc_context_start_read(&data->ctx, sequence); |
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.
Break a line here.
Hi @erwango , I added some comments and fixed style issues, how about this time? |
All series of stm32 have at least one ADC instance and this commit adds one ADC node to the root dts file of each soc, and also adds fixing up mappings to them. Signed-off-by: Song Qiang <songqiang1304521@gmail.com>
This commit adds pinmux defines for all the external ADC lines supported by stm32. All defines are named after the datasheet of the corresponding product lines. Signed-off-by: Song Qiang <songqiang1304521@gmail.com>
This commit adds driver support for ADC1 on all 8 supported series of stm32 with resolution and conversion time selection and calibration. Currently DMA is not supported for all series, and without it, zephyr won't be able to catch up ADC's end of conversion interrupt, so this version of the driver supports one channel conversion only. Users want multi-channel conversion should use multiple sequences in their app code. This driver uses LL lib rather than HAL because the current HAL lib for ADC will call HAL_DMA_* functions rather than using zephyr's common DMA interface, so that way the driver will break the consistency of the code. This driver has been tested on multiple nucleo boards including NUCLEO_F091RC/F103RB/F207ZG/F302R8/F401RE/F746ZG/L073RZ/L476RG and all passed the test cases in tests/drivers/adc/adc_api. If the external ADC line is floating, it may fail the tests since ADC may get 0V and the test cases think 0 is failing. Connect it to any voltage source between 0-3.3V will help passing the test cases. Signed-off-by: Song Qiang <songqiang1304521@gmail.com>
Some configuration for the boards have to be added into test_adc.c file so user can test driver with the test cases. Several nucleo boards are added including F091RC/F103RB/F207ZG/F302R8/F401RE/F746ZG/L073RZ/L476RG. And also ADC dts and pinmux configuration are added into boards own pinmux.c and dts file. Signed-off-by: Song Qiang <songqiang1304521@gmail.com>
The ADC driver in this PR has been tested working on these nucleo boards, so ADC support is added to the boards doc. Signed-off-by: Song Qiang <songqiang1304521@gmail.com>
This PR contains pinmux, dts and driver support for ADC1 for all series of stm32 that zephyr supports.