-
Notifications
You must be signed in to change notification settings - Fork 6.7k
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
stm32f4 uart and adc enhancement #8624
Conversation
Codecov Report
@@ Coverage Diff @@
## master #8624 +/- ##
===========================================
- Coverage 64.17% 52.41% -11.77%
===========================================
Files 429 198 -231
Lines 41161 24912 -16249
Branches 6926 5185 -1741
===========================================
- Hits 26416 13058 -13358
+ Misses 11587 9754 -1833
+ Partials 3158 2100 -1058
Continue to review full report at Codecov.
|
Is this driver using the new ADC API that is in #7691 |
Hi @StefJar , Thanks for proposing this driver! Some comments to begin:
Thanks |
I am happy to get some quick feedback on my first pull. I am new to zephyr and is infrastructure. Pls help me to understand. So how to carry on? @hal: @C/C++: @split: shure |
dts/arm/st/stm32f4-pinctrl.dtsi
Outdated
@@ -27,6 +27,12 @@ | |||
tx = <STM32_PIN_PB6 (STM32_PINMUX_ALT_FUNC_7 | STM32_PUSHPULL_NOPULL)>; | |||
}; | |||
}; | |||
usart1_pins_d: usart1@3 { | |||
rx_tx { | |||
rx = <STM32_PIN_PA10 (STM32_PINMUX_ALT_FUNC_7 | STM32_PUSHPULL_PULLUP)>; |
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.
Not sure it is actually required (I've never mucked with the drive settings for UARTs on STM32) but the other definitions are using STM32_PUPDR_NO_PULL
.
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.
True ´- it's a copy and paste error. Still seems to work. ha ha
As mentioned, for rx no resistor is needed.
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.
changes regarding rx pin are done
dts/arm/st/stm32f4-pinctrl.dtsi
Outdated
@@ -27,6 +27,12 @@ | |||
tx = <STM32_PIN_PB6 (STM32_PINMUX_ALT_FUNC_7 | STM32_PUSHPULL_NOPULL)>; | |||
}; | |||
}; | |||
usart1_pins_d: usart1@3 { | |||
rx_tx { | |||
rx = <STM32_PIN_PA10 (STM32_PINMUX_ALT_FUNC_7 | STM32_PUSHPULL_PULLUP)>; |
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.
True ´- it's a copy and paste error. Still seems to work. ha ha
@StefJar :
You could define whatever ADC instance exist in whole STM32 family here.
Good, thanks
CI is continuous integration. Whenever you push or update a PR automatics tests are performed. Some are done on style and some on code. Reports are provided by 'Shippable' down here: 'All checks have failed'. So you should provide some comment in the commit message (also, if you look to a git tree, you'll see all commits have a message) |
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.
Some additional comments on style, otherwise you'r doing good.
Would be nice to introduce device tree support. For exemple of adc node, you could have a look to : https://elixir.bootlin.com/linux/v4.18-rc3/source/arch/arm/boot/dts/stm32f429.dtsi#L465
|
||
if ADC_STM32F4 | ||
|
||
menu ADC_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.
Don't indent here. Kconfig files should remain flat
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.
think the best solution would be a flat ADC driver + the instance setup (like channels) in the dts. Never done this before. Is there a document/example that describes how to connect between dts node and 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.
@StefJar , there is a doc there: http://docs.zephyrproject.org/devices/dts/device_tree.html
To sum up:
1- Populate the node in device tree (you can base initially on linux dts)
2- Provide a yaml file (here: dts/bindings/iio/adc/
) to instruct dts script on how to interpret the adc node. File name should be same as node compatible. With this, at build, you should get a bunch of #define's generated in output folder, in zephyr/include/generated/generated_dts_board.h
.
3-Provide CONFIG_XXX to generated #define's matching in .fixup files (arch/arm/soc/st_stm32/stm32f4/dts.fixup
for series)
4- Define HAS_DTS_ADC for the series where adc device node is populated
Then you're good to use whatever values populated in device tree directly in your 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.
Then you're good to use whatever values populated in device tree directly in your driver
Note that the device tree should describe the hardware, not the configuration.
It would be better to check the Linux driver (https://elixir.bootlin.com/linux/v4.17/source/drivers/iio/adc/stm32-adc-core.c and https://elixir.bootlin.com/linux/v4.17/source/drivers/iio/adc/stm32-adc.c) and corresponding DTS binding (https://elixir.bootlin.com/linux/v4.17/source/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt) to make sure that we stay compatible.
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.
merci - I will take a deeper look when I have time for that
drivers/adc/Kconfig.stm32f4
Outdated
select USE_STM32_HAL_ADC_EX | ||
select USE_STM32_HAL_CORTEX | ||
help | ||
Enable the driver implementation for the stm32f4xx 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.
Text of 'help' section should be indented by 2 spaces (you can look at other files as exemple)
drivers/adc/adc_stm32f4.c
Outdated
/* adc_dw.c - Designware ADC driver */ | ||
|
||
/* | ||
* Copyright (c) 2015 Intel Corporation |
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.
Put your own Copyright here.
// none | ||
break; | ||
} | ||
if(GPIOport) HAL_GPIO_Init(GPIOport, &gpioCfg); |
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.
In Zephyr base code, we enforce the use of braces, even for one liners.
This should looks like:
if(GPIOport) {
HAL_GPIO_Init(GPIOport, &gpioCfg);
}
drivers/adc/adc_stm32f4.c
Outdated
activeChannels = config->activeChannels; | ||
i = adcChannel_0; | ||
rc = stm32adcError_None; | ||
while(activeChannels) { |
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.
Put a space after while
, do the same after if
's.
Apply everywhere
drivers/adc/adc_stm32f4.c
Outdated
SYS_LOG_INF("init adc%u", (unsigned int)config->adcDevNum); | ||
|
||
switch(config->adcDevNum) { | ||
#ifdef CONFIG_ADC_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.
Put #ifdef
at the start of a line
@@ -0,0 +1,82 @@ | |||
// |
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 use following template for copyright:
/*
* Copyright (c) 2015 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.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.
Hi, I did a quick review to point out some problems, mostly style issues that can be easily addressed.
I think that the ADC driver could be greatly simplified by configuring the channels at runtime.
As mentioned by another reviewer, it would be also good to make it more generic to run on other families. Thanks.
default n | ||
depends on ADC_0 | ||
help | ||
Enables ADC channel 0 at pin PA0 |
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 would not mention the pin, as it will probably change between families (ADC1_IN0 is connected to Vrefint on STM32L4 for instance). But I would propose to drop these Kconfig completely (see below).
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 we can do the configuration of the driver instance in the dts?
Think configuration in run time is a waste of resources. We do not need to check the config before every adc conversion. It can be checked at the init of the driver once(and then never again)
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.
DTS is only to describe the hardware, not the configuration.
I agree that configuring at runtime will have a cost, but it is way more flexible. Static configuration may be OK for a simple project, but it is not enough for a more complex usecase. Think for example that you may have to reconfigure your ADC at several points in the lifetime of your product's lifecycle (i.e. production/testing, shipping, everyday use, low-power saving mode, etc.), which is not possible with the current implementation.
I do not remember if the new ADC API is better with respect to this point.
drivers/adc/adc_stm32f4.h
Outdated
|
||
|
||
//! type and enum for channel ids | ||
typedef enum adcChannels { |
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.
Zephyr follow Linux coding style, so you should use snake_case instead of camelCase for identifiers, function names, etc.
// | ||
// @return Integer: 0 for success, error otherwise. | ||
// | ||
int adc_stm32f4_init(struct device *dev); |
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 is this function public? It should not be necessary to call it by hand if you use DEVICE_INIT
or a similar macro (see include/device.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.
there was no "How to write an (ADC)driver?". I used the adc_dw as blueprint. It was in there so it means for me that it had its relevance. Don't ask me why ;)
|
||
#ifdef CONFIG_ADC_0 | ||
|
||
struct adc_drvData adc_drvData_dev0 = { |
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.
static
and the closing brace should not be indented (it is even not needed at all as you perform no initializations).
}; | ||
|
||
static struct adc_config adc_config_dev0 = { | ||
.adcDevNum = 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.
It looks like there is too much indentation, only one tab is needed.
} | ||
SYS_LOG_INF("use %u multiplexed channels", (unsigned int) drvData->hadc.Init.NbrOfConversion); | ||
|
||
// start the 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.
Nit: this does not really start the ADC, but configure it.
} | ||
activeChannels >>= 1; | ||
i++; | ||
} |
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 that configuring the channels at compile time is a bit limiting:
- It adds a looooot of Kconfigs
- You cannot have several sets of sequences, so it limits to basic usecases
- You cannot specify the order inside the sequence, which might be important depending on what hardware you sample
Why not configuring the channels in the .read
callback using seq_table
? In addition this is way easier to perform, so it would remove a good chunk of code.
I agree that this API is limiting, but hopefully the next iteration will be better.
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.
To implement this we need to check/setup the adc sequencer at each adc run. This will cost some computing time. Think usually the user has a static setup which does not change at runtime.
A limiting factor to the sequencing structure is, that you can not define a real delay between the conversation of the channels. This Zephyr feature is not supported by the stm32f4 hardware. Of course we can try to add this via software. But is this really needed?
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.
Unfortunately this is not my setup, I need to reconfigure the ADC sequence at runtime to address some complex needs.
I do not use the conversion delay from the sequencing structure so this is not really a problem for me.
drivers/adc/adc_stm32f4.c
Outdated
|
||
SYS_LOG_INF("init adc%u", (unsigned int)config->adcDevNum); | ||
|
||
switch(config->adcDevNum) { |
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.
You should have a space between the keyword and the opening parenthesis switch (
. Same applies to if
, for
, etc. This is following the Linux coding style.
// none | ||
break; | ||
} | ||
if(GPIOport) HAL_GPIO_Init(GPIOport, &gpioCfg); |
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 initializing the GPIO? This should not be needed for the ADC to work as we should multiplex the pin as analog. This removes most of the complexity of this function, not mentioning that it is not portable across families.
{ | ||
const struct adc_config *config = dev->config->config_info; | ||
|
||
SYS_LOG_DBG("adc%u enable", (unsigned int)config->adcDevNum); |
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.
You should calibrate the ADC before using it with a call to HAL_ADCEx_Calibration_Start()
.
Thanks for the feedback. I am on it. |
…e reading for an interrupt in that a semaphore is set. No STM32HAL waiting - instead use of sem_take function.
done some of the changes. Major change is the switch to isr based adc conversion. |
As @galak mentionned, ADC API (now merged into How specific ADC and UART drivers are to stm32f4? Should not they be specific to STM32? |
@StefJar , any update? |
I "unmerged" my stm32 adc driver out of my zephyr kernel after the last major adc driver api changes. |
Added some features for the stm32f4xx MCUs
simple stm32hal based ADC driver.
Channels configurable through menuconfig.
Pin config for ADC channels are done inside the driver. no connect to the pinmux so far.
ADC channel conversion time is fixed so far.
driver is an alpha