Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
ADC tests #6
I've been testing ADC functions.
1. Issue with _weak prototypes for interrupt functions in stm32f4xx_hal_adc.c
When I started working on ADC interrupts I got the following error:
...Arduino\hardware\STM32GENERIC\STM32\system/STM32F4/HAL_Src/stm32f4xx_hal_adc.c:958: undefined reference to `HAL_ADCEx_InjectedConvCpltCallback'
For some reason the _weak prototype for HAL_ADCEx_InjectedConvCpltCallback( ) at stm32f4xx_hal_adc_ex.c : 769 isn't providing coverage, when the function isn't needed.
Including a null routine in the user code fixes this issue (not ideal) - the additional null routine isn't required in Frederic's implementation.
2. ADC Extended functions missing
The extended ADC functions in stm32f4xx_hal_adc_ex.c are not available.
The solution is to add the second #include in the code below at stm32f4xx_hal_conf.h : 269
I suspect the library spl.a might need recompilation as well - as including the stm32f4xx_hal_adc_ex.h file in user code, or in stm32f4xx_hal_conf.h, doesn't make the error go away.
This is because not every HAL is compiled in.
The reason is compilation time. If compilation time was not a problem, I would just put everything in the core.
I will move the mostly used ones (adc_ex, sdram, dac, ), and put the others in menu item maybe... I don't know.
yes, it works now.
I have working ADC HAL demos for:
I can see no reason why they shouldn't work for all F4s.
They are uploaded to my repo at: https://github.com/palmerr23/Black-F407VET6-STM32Generic
I agree that a tidy-up might be nice to make things more simple, and a ready reference for the options available for ADC_Config() . The readme.txt files for the examples are helpful, but quite wordy. I deleted a few, and have edited and reinstated them. There are a some good general tutorials already online, e.g. http://embedded-lab.com/blog/stm32-adc-2/ maybe a short how-to might be in order - I'll have a think about this.
Experience has shown that for the ADCs, once you get past the basic "read a value", the code always gets tweaked one way or another. Having an overly clever API gets in the way, particularly if the need is for fast response or high data rates (not using DMA). If anything, mixed HAL / LL usage is the direction things tend to go if there's a serious need for ADC.
In the Teensy space, Pedro Villanueva's ADC library is the benchmark, I believe. https://github.com/pedvide/ADC
He implements a set of per-parameter function calls, e.g. setResolution(), rather than filling in a full Init structure and then passing it to a master config routine (which seems to be the STM approach for both HAL and LL). Both are valid and equally useful.
When I developed a set of Teensy-based audio limiters with sub millisecond attack late last year, I used Pedro's config routines and then wrote the ADC interrupt handler from scratch.
@ollie and I have just been discussing high-level vs low-level library support in the Stm32duino forums http://stm32duino.com/viewtopic.php?f=39&t=1977&start=50
Our conclusion - keep it simple and STM standardised at the library level with a broad set of examples for folks to adapt.
Exceptions to this for ADCs might be measureVBAT() or measureChipTemp() which could be delivered through a standard API. Sadly, they are only useful in very specific circumstances. Any decent library written for battery operation will manage VBAT configuration directly. ChipTemp is not much use, except for hostile operational environments.
Can you think of any places where there would be substantial improvements via a higher level API?
Some overnight thinking...
Except for multi-mode, a single ADCinit(ADCx, ADCpin, SampleTime, Resolution, ADCmode) could work. Mode would combine Single/Continuous, Interrupt/DMA/Polling option and single/multiple channels. These could be broken out into several variables, but that might allow some combinations that are illegal (or silly).
For multi modes, ADCx would be ignored and an optional SampleDelay parameter would be needed at the end. It could also be added to the ADCstart() function below.
If multiple Channels are to be converted, either a function with variable length arguments, or passing an array of pins could work, issued before ADCstart()
ADCsetChannels(ADCx, channelArray) - ADCinit(...ADCpin...) could be set to MULTICHANNEL == -1
External/timer triggers could be handled in a similar way. ADCtrigger(ADCx, TrigVal) could be issued before ADCstart.
ADCstart(ADCx, nSamples) and a local handler for Interrupts (DMA/ADC) would be needed for non-polling modes. The rest could be handled in the library.
Special functions could handle the uncommon options e.g. DataAlignLeft.
Does this approach appeal?
The Class option is excellent where there might be a need for multiple independent instances - e.g. displays, external hardware, particularly where they need to be logically isolated and the data structures instanced on the fly.
Pedro uses this approach with the Teensy library.
When you're dealing with an internal peripheral, particularly one where synchronisation between instances (multimode) is needed, there's not much benefit. As well, the ADC data structures are already instanced via the #includes for the ADCs - which is quite sensible as there are a small, fixed number of ADCs.
That's a personal view, and I'd be keen to hear Frederic's viewpoint - as there are multiple benefits in a common approach.
On the API front, another option (Pedro used this one), is to have a set of atomic functions to do various simple tasks, where there aren't complex interactions: setResolutionADC(16), setSampleTimeADC(56), etc
Then have a start() function for each operating mode e.g. startSynchronizedSingleRead()
This reduces the number of parameters in the specific mode calls, which is a good thing!
Here's a set of atomic ADC config functions from http://embedded-lab.com/blog/stm32-adc-2/
I'm not sure this is really any better than setting the values in an init structure. The main issue is the combination of settings needed to get things going properly can be quite confusing.