-
Notifications
You must be signed in to change notification settings - Fork 1k
Introduce new ADC API for DMA-based high sampling rate #175
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
Conversation
cores/arduino/stm32/dma.c
Outdated
"-' "-- | ||
|
||
---------------------------------------------------------------------------- | ||
|
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 ASCII art 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.
It's remove
cores/arduino/stm32/dma.c
Outdated
#endif | ||
|
||
extern ADC_HandleTypeDef AdcHandleTab[ADC_NUM]; | ||
|
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.
dma.c file should not have any reference to ADC, so that it can later be re-used by oher devices
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.
We will see if it possible in next release.
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.
After study, it's not possible to remove this variable from DMA. The DMA link a peripheral, it need to have the information that is in the ADC structure. If we don't share this variable between ADC and DMA, DMA will not work.
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.
The idea was to do the DMA allocation in dma.c and keep the dma actual configuration in each driver ADC and others later. Otherwise this file here will become huge and needs to be updated each time when you need to add DMA support for a new driver. If we make this file simpler, then up to each driver to add the calls to DMA based on the "allocated" DMA information. My point is not that the code is wrong, but rather the split between the files can be changed
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.
If i understand well, dma_allocate() just give you the irqHandler and the channel to use, then all the initialization of the DMA will be done in analog.c file, in HAL_ADC_MspInit() function.
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 would be the idea of the proposal indeed - please think about it and let let me know if you think it makes sense. Also I think that the DMA mapping table can be generic and could contain any kind of peripheral instances (ADC, serial, I2C, etc ... ) so the name and types should be generic
Depending on peripherals that are used, the DMA settings will differ (periph to mem, or mem to periph, etc.) so it is rather up to the peripheral driver to set these options.
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.
Done, let me know if it's OK. I didn't rebase the git history yet if you want to go back.
cores/arduino/stm32/dma.c
Outdated
__HAL_RCC_DMA2_CLK_ENABLE(); | ||
#endif | ||
|
||
channel = pinmap_find_dmaChannel(hadc->Instance, DmaMap_DMA); |
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.
Instead of DmaMap_DMA a generic table can be used, where any kind of devices Serial, ADC could be listed with corresponding ADC instance and channel. ...
Then the table could be parsed with a for loop instead of checks like (if (hadc->Instance == ADC3))
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.
pinmap_find_dmaChannel is similar to other functions like pin_pinName or pinmap_find_function. Why should it be different? DmaMap_DMA contains all informations needed for DMA like PinMap_ADC contains all informations needed for 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.
One important thing: PeripheralsPins.c contains arrays for pin mapping.
What a pin is able to do for a dedicated peripheral and how.
So adding this kind of array not linked to a pin is not correct.
+const DmaMap DmaMap_DMA[] = {
- {ADC1, 1, DMA1_Channel1, DMA1_Channel1_IRQn , 1},
- {ADC1, 1, DMA1_Channel2, DMA1_Ch2_3_DMA2_Ch1_2_IRQn, 2},
- {ADC1, 2, DMA2_Channel5, DMA1_Ch4_7_DMA2_Ch3_5_IRQn, 5},
- {NP, 0, NP, NP, 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.
A DMA is link to a peripheral not a pin... i agree we that. Can we keep this table an put it in another file? Oterwise, what do you propose?
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.
Currently, I do not reviewed this PR so I have no proposal. Just a note on PeripheralPins.c file usage.
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 agree with proposal to keep the table that is needed but move it to dma.c as this is a table about dma channels and streams, not pins - is it ok ?
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.
The table if different from one board to another. If we move it to dma.c, we will frame it with #ifdef. dma.c will become a huge file. Is it ok for you?
cores/arduino/stm32/dma.c
Outdated
|
||
channel = pinmap_find_dmaChannel(hadc->Instance, DmaMap_DMA); | ||
#ifdef ADC1_BASE | ||
if (hadc->Instance == 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.
rather use a for loop over the DMA descritpion table for finding a match.
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.
We need to know is the ADC exist before the "if" condition. Some device have only one ADC...
The same method is used in timer.c
cores/arduino/stm32/dma.c
Outdated
|
||
/* Deinitialize & Initialize the DMA for new transfer */ | ||
HAL_DMA_DeInit(&DmaHandleTab[indice]); | ||
HAL_DMA_Init(&DmaHandleTab[indice]); |
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.
Once DMA instance and channel are found, the DMA init itself could be left in the ADC 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.
Is it not better to do all the DMA things in DMA layer?
cores/arduino/stm32/dma.c
Outdated
* @retval none | ||
*/ | ||
void dma_init_adc(ADC_HandleTypeDef *hadc) | ||
{ |
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.
As mentioned DMA PAI should not mention ADC at all.
instead of dma_init_adc I would rather consider a generic function like dma_allocate to look for the proper DMA instance and channel with a generic (void*) pointer to device. then the function would look for an instance match in the table with pinmap_find_dmaChannel.
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.
dma_allocate create. A enum is create, we need it for identify the peripheral.
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 I don't understand your answer.
My proposal is
replace : void dma_init_adc(ADC_HandleTypeDef *hadc)
by : void dma_init(void *any_handle_typedef)
so that it can later be used also by other devices than 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.
This is what we have done. But in dma_init() we also need an other parameter for know on what peripheral we work (ADC, UART). So the prototype is :
void dma_allocate(void *periph_handle, Peripheral periph);
cores/arduino/stm32/dma.c
Outdated
* @retval none | ||
*/ | ||
void dma_deinit_adc(ADC_HandleTypeDef *hadc) | ||
{ |
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.
rathe have dma_free or dma_put to release a DMA handle.
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.
dma_free() is create. The prototype is void dma_free(void *periph_handle, Peripheral perip).
Again, we need to know on which peripheral we work.
cores/arduino/stm32/dma.c
Outdated
{ | ||
HAL_DMA_IRQHandler(AdcHandleTab[0].DMA_Handle); // ADC1 | ||
} | ||
else |
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.
could be
elsif (AdcHandleTab[0].DMA_Handle != NULL)
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 don't really understand what you mean. If and elseif can't have the same condition. I can put a condition on the elseif if that's what you want.
* @retval None | ||
*/ | ||
|
||
#ifdef ADC1_BASE |
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.
Wouldn't it be better to keep generic name ?
DMA1_Channel1_IRQHandler
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.
We can't keep generic name because the are different from one device to another. For example for F3 family this is DMA2_Channel1_IRQHandler and for F4 family this is DMA2_Stream1_IRQHandler. (Channel/Stream)
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 I understand that - I just mean is it really needed that the name contains 'ADC'
it could be always DMA2_Stream1_IRQHandler anyway and redefined only for few families.
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 done in next release.
cores/arduino/stm32/dma.c
Outdated
defined(STM32F098xx) | ||
void DMA_ADC1_IRQHandler3(void) | ||
{ | ||
HAL_DMA_IRQHandler(AdcHandleTab[0].DMA_Handle); |
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 checking handle is != NULL ?
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.
Done. Null pointer is check.
/*##-2- Configure peripheral GPIO ##########################################*/ | ||
#ifdef ADC1_BASE |
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.
How is this part of change related to "prepare ADC DMA for F3 family" ?
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 was a old commit, i rename it.
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 for the new split asa it is started now. More changes are required I think. Please find more comments and proposals as well.
cores/arduino/stm32/PeripheralPins.h
Outdated
@@ -71,5 +71,8 @@ extern const PinMap PinMap_Ethernet[]; | |||
//*** QUADSPI *** | |||
extern const PinMap PinMap_QUADSPI[]; | |||
|
|||
//*** DMA *** | |||
extern const DmaMap DmaMap_DMA[]; | |||
|
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.
as suggested by @fpistm the DmAMap should be declared and managed in dma.c, not in PeripheralPins as there is no pin in this map.
cores/arduino/stm32/dma.c
Outdated
*channel = pinmap_find_dmaChannel(hadc->Instance, DmaMap_DMA); | ||
|
||
/* Set clock as active */ | ||
channelNumber = pinmap_find_dmaChannelNumber(hadc->Instance, DmaMap_DMA); |
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 should not be pinmap_find_dmaChannelNumber but dma_find_dmaChannelNumber
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.
Done
cores/arduino/stm32/dma.c
Outdated
|
||
/* Set clock as active */ | ||
channelNumber = pinmap_find_dmaChannelNumber(hadc->Instance, DmaMap_DMA); | ||
dmaNumber = pinmap_find_dma(hadc->Instance, DmaMap_DMA); |
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
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.
done
cores/arduino/stm32/dma.c
Outdated
void DMA2_Stream0_IRQHandler(void) | ||
{ | ||
#if defined(STM32F2xx) || defined(STM32F4xx) || defined(STM32F7xx) | ||
if (AdcHandleTab[0].DMA_Handle != NULL) |
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.
from dma point of view this is a HandleTab, we don't need to to know it's a Adc one.
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.
Where is the DMA_Handle table initiliazed with proper DMA_handle values ?
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 done by this function, when your link the DMA to a peripheral :
__HAL_LINKDMA(hadc, DMA_Handle, DmaHandleTab[indice]);
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 same as previous - I have looked at __HAL_LINKDMA and this is now clearer. thanks
cores/arduino/stm32/pinmap.c
Outdated
@@ -109,3 +109,39 @@ PinName pin_pinName(const PinMap* map) { | |||
return (PinName)NC; | |||
} | |||
} | |||
|
|||
uint8_t pinmap_find_dma(void* peripheral, const DmaMap* dma) { |
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.
DMA functions that are not related to pins should be moved to dma.c file
cores/arduino/stm32/analog.c
Outdated
static PinName g_current_pin = NC; | ||
void (*cb[ADC_NUM])(void *user_data); | ||
static bool use_dma = false; |
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 isn't a "use_dma" for each ADC like use_dma[ADC_NUM] ?
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.
Here we don't need a table. I explain myself. When you want to use ADC peripheral with or without DMA, the same function was called : HAL_ADC_MspInit(). In this function I do the DMA part only if the call come from the dma function (adc_read_value_dma). The boolean dma_use fulfilled this role.
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.
so does it cover the case where ADC_1 is used with DMA and ADC_2 is used without DMA ?
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
cores/arduino/stm32/analog.c
Outdated
*/ | ||
ADC_HandleTypeDef AdcHandleTab[ADC_NUM]; | ||
static DMA_HandleTypeDef DmaHandleTab[ADC_NUM] = {NULL}; | ||
static PinName g_current_pinTab[ADC_NUM]; | ||
static PinName g_current_pin = NC; |
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.
looks like g_current_pin is not used anymore 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.
It's used for DAC function, I don't touch to this part. See for example function HAL_DAC_MspInit() or dac_write_value().
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.
hmm ok - can we use the same DAC in DMA then without DMA ? Isn't it supposed to be the same pin .
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.
Do you want to use g_current_pinTab for DAC too? I prefer to leave as it is because DAC and ADC are two different peripherals.
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 - no please keep them separated if they're used for different purpose. But would be great to have at a least a comment to explain that one is used for ADC and the other one is used for DAC because as of now they have exactly the same name.
cores/arduino/stm32/analog.c
Outdated
*/ | ||
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *AdcHandle) | ||
{ | ||
void *user_data = NULL; |
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.
what's the point of user_data if it is always NULL ?
cores/arduino/wiring_analog.c
Outdated
@@ -61,6 +61,21 @@ uint32_t analogRead(uint32_t ulPin) | |||
return value; | |||
} | |||
|
|||
//Start a DMA acquisition on ADC | |||
//the initialization of the analog PIN is done through this function | |||
void analogReadDma( uint32_t ulPin, uint32_t *pData, uint32_t lData, void (*callback)(void *user_data)) |
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.
if we use a user_data parameter in the callback, then the user data paramrter must also be passed by application.
cores/arduino/stm32/analog.c
Outdated
static PinName g_current_pin = NC; | ||
void (*cb[ADC_NUM])(void *user_data); | ||
static bool use_dma = false; | ||
|
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 it would be useful to have a global ADC structure starting which would contain the ADC handle, the DMA handle, cb and also use_dma I guess.
+ADC_HandleTypeDef AdcHandleTab[ADC_NUM];
+static DMA_HandleTypeDef DmaHandleTab[ADC_NUM] = {NULL};
+static PinName g_current_pinTab[ADC_NUM];
+void (*cb[ADC_NUM])(void *user_data);
+static bool use_dma = false;
If you define your structure in such way that ADC_HandleTypeDef is the first structure parameter, then you can also access the global structure based on the handle.
something like
typedef struct {
ADC_HandleTypeDef AdcHandle;
DMA_HandleTypeDef DmaHandle;
PinName current_pin;
void(*cb)(void user_data);
void user_data;
bool use_dma;
} adc_context;
static adc_context context(ADC_NUM];
then in MSp_Init/Deinit and also in HAL_ADC_ConvCpltCallback you can get all information like cb:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef AdcHandle) {
adc_context context = (adc_context *) AdcHandle;
if(context->cb != NULL)
context->cb(context->user_data);
}
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.
Done. New release available.
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.
Looks pretty good now. Only a few remaining comments or questions.
cores/arduino/stm32/dma.c
Outdated
{ADC3, 2, DMA2_Stream1, DMA2_Stream1_IRQn, 1}, | ||
#endif | ||
#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.
isn't the table supposed to end with NP 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.
Yes. Done.
cores/arduino/stm32/analog.c
Outdated
AdcContext context[ADC_NUM]; | ||
|
||
/* DMA is use, or classic ADC */ | ||
static bool use_dma = false; |
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 still don"t understand why use_dma is not defined for each instance ... how does it work in case ADC1 is used in DMA mode wile ADC2 is used without DMA.
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 right, i see where is the problem. My thing works only for initialization, but I have lost the use_dma information when I wat Deinit it. So yes it's better to make a use_dma for each instance.
cores/arduino/stm32/analog.h
Outdated
@@ -47,6 +57,15 @@ | |||
extern "C" { | |||
#endif | |||
|
|||
typedef struct { | |||
ADC_HandleTypeDef AdcHandle; |
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.
We're making sure that AdcHandle is the first struct inside AdcContext => add a comment to make sure this is always true.
*/ | ||
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *AdcHandle) | ||
{ | ||
/* Report to main program that ADC sequencer has reached its end */ |
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.
Because we're making sure that ADC_HandleTypeDef is the first struct in the AdContext struct this is a trick to retrieve the AdcContext from the handle used in HAL.
you should be able to code as below:
AdcContext context = (AdcContext *) AdcHandle;
contex.cb(context.user_data);
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. Done. New release available.
Signed-off-by: dhl <[email protected]>
Signed-off-by: dhl <[email protected]>
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 for this release.
Thanks @damienWi6labs |
PR description update. |
@fpistm - anything gating this PR ? |
My review of DMA API... |
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.
Major remark is that ADC uses DMA service.
DMA service must be generic and must not be aware of any peripheral in its code. This is to the peripheral to provide the right config with the right handler.
For DMA, ADC instance or SPI one is the same.
Commits order have to be changed. DMA api must be introduced before using it.
Provide a Wiki page about this new API: analogReadDma in https://github.com/stm32duino/wiki/wiki/API
Provide a sketch example in STM32Examples repo or in the Wiki
@@ -47,6 +57,16 @@ | |||
extern "C" { | |||
#endif | |||
|
|||
typedef struct { | |||
ADC_HandleTypeDef AdcHandle; /* CAUTION : This must be this first element of the struct */ |
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, explain why in the comment
#else | ||
#error "ADC SAMPLINGTIME could not be defined" | ||
#endif | ||
|
||
// Use smaller clock prescaler to keep ADC conversion time as short as possible |
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 it really true as this depends of the series and which source clock is used?
Ex:
F0 has no ADC_CLOCK_SYNC_PCLK_DIV1. So ADC_CLOCK_ASYNC_DIV1 will be used but this one is:
ADC asynchronous clock derived from ADC dedicated HSI while ADC_CLOCK_SYNC_PCLK_DIV2 is ADC synchronous clock derived from AHB clock divided by a prescaler of 2.
Moreover for L0: which is the best to use?
ADC_CLOCK_ASYNC_DIV1 or ADC_CLOCK_SYNC_PCLK_DIV1?
Note that ADC_CLOCK_SYNC_PCLK_DIV1 must be enabled only if PCLK has a 50% duty
clock cycle (APB prescaler configured inside the RCC must be bypassed and the system clock
must by 50% duty cycle)
* @{ | ||
*/ | ||
/* Adc context */ | ||
AdcContext context[ADC_NUM]; |
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.
typo use upper case:
ADCContext
Table should be rename ADCContextMap
to better identify it.
Then the structure have to be rename to know it is a structure typedef: ADCContext_t
ADCContext
could be used for variable
/** @addtogroup STM32F4xx_System_Private_Variables | ||
* @{ | ||
*/ | ||
/* Adc context */ |
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.
typo use upper case for ADC:
ADC
/* Adc context */ | ||
AdcContext context[ADC_NUM]; | ||
|
||
/* GPIO pin use for DAC */ |
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.
Only for DAC ?
typedef struct { | ||
void* peripheral; | ||
int8_t dmaNumber; | ||
void* channel; |
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.
As the dmaNumber and channelNumber, it's possible to retrieve void* channel;
So dma_find_dmaChannel
could be rewrote to return the correct one.
This will save some space.
Moreover, for struct memory alignement put channelNumber
next to dmaNumber
/* NVIC configuration for DMA Input data interrupt */ | ||
*irqHandler = dma_find_dmaIrqHandler(instance, DmaMap_DMA); | ||
|
||
#ifdef __HAL_RCC_DMA1_CLK_ENABLE |
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.
As the DMA instance used is know, enable only the right one.
/*##-3- Ask DMA informations ###############################################*/ | ||
if (dma_allocate(hadc->Instance, &channel, &irqHandler)) | ||
{ | ||
/*##-4- Configure the DMA ##################################################*/ |
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.
DMA configuration have to be done by the driver in dma.c
dma_init()
#include "dma.h" | ||
#include "analog.h" | ||
|
||
const DmaMap DmaMap_DMA[] = { |
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.
ADC DMA mapping have to be in analog part:
ADC1 , 1 ,1 --> ADC1 use DMA1 channel 1
In dma: only the dma handle should be stored
if (context[indice].use_dma) | ||
{ | ||
dma_free(hadc->Instance); | ||
HAL_DMA_DeInit(hadc->DMA_Handle); |
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.
dma_free should be called after deinit ?
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.
Major remark is that ADC uses DMA service.
DMA service must be generic and must not be aware of any peripheral in its code. This is to the peripheral to provide the right config with the right handler.
For DMA, ADC instance or SPI one is the same.
Commits order have to be changed. DMA api must be introduced before using it.
Provide a Wiki page about this new API: analogReadDma in https://github.com/stm32duino/wiki/wiki/API
Provide a sketch example in STM32Examples repo or in the Wiki
Hi @fprwi6labs |
Hi @fprwi6labs, |
Implement DMA API for ADC for F0, F1, F3, F4, L0 and L4 families. The DMA is used for maximize the ADC sampling rate. Measure the sampling rate for each ADC and verify that they match the datasheet. For example on L4 board measure a sampling rate of 5,33 Ms/s on the three ADCs. Also check that we can make two ADC conversions at the same by using the DMA with two differents ADCs.