cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U5 ADC4: possible to enable DMA and AWD at the same time?

OpusOne
Associate II

Hello, as the title goes: is it at all possible to enable both DMA and an analog window watchdog (AWD1) simultaneously on the ADC4?

What I'm trying to achieve is the following:

  1. ADC4 configured to operate in Stop2 mode and triggered by LPTIM1/CH1 (PWM), clocked by MSIK.
  2. AWD1 enabled and also in autonomous mode so it works in Stop2 mode and can wake-up the CPU.
  3. DMA enabled at the same time and filling a buffer with the ADC4 acquisitions, same channel as the one which has AWD1 enabled, using LPDMA1, also configured to work autonomously in Stop2.

I managed to make the first 2 points work and I'm pretty happy with the results: I get an average current of ~ 7 µA (SMPS enabled) in Stop2, with ADC4 sampling at 500 Hz autonomously (triggered by LPTIM1/CH1) and AWD1 working as expected. So that's pretty good.

I then tried to implement a DMA transfer concurrently on the same ADC4 channel using LPDMA1, and this is where things go wild. DMA transfers and AWD1 on ADC4 don't seem to play well together. I haven't read anything particular about it in the reference manual or in the errata, but I may have missed it.

First issue when doing this is that the DMA seems to get only 1 request every 2 ADC conversions.

Second issue, that seems only related to enabling DMA transfers in ADC4, regardless of whether I enable a DMA channel or not. When setting the transfer mode with:

 

 

LL_ADC_REG_SetDMATransfer(ADC4, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);

 

 

I get a very odd behavior of the MCU that seems related to the debug IP. Let me elaborate:

  1. When the STM32U5 has enabled its debug IP (which happens when we access it through SWD), it draws ~ 160 µA in Stop2 mode, and from what I've read, that's normal behavior. This extra power draw only disappears after a power cycle of the chip.
  2. When the debug IP is enabled, but I set the above (DMA transfer enabled for ADC4, then ADC4 enabled), instead of drawing ~ 160 µA in Stop2, it draws only ~ 55 µA. It caught my attention because I found this change odd, and tracked it down to just enabling DMA transfers in ADC4 and then enabling ADC4 (with its autonomous clock enabled) and going to Stop2.
  3. Once that has happened (MCU gone in Stop2 mode with DMA enabled for ADC4), not only the current draw looks abnormal, but the debug IP acts in abnormal ways - SWD connection gets lost randomly (I'm using a STLINK V3) while it never happens otherwise. Power-cycling the MCU gets it back to normal.

I haven't read anything related to that in the errata, but maybe I missed it.

Thanks for any pointers about these 2 issues!

Edit: I just want to add to this that it's the "unlimited" DMA mode (circular mode in the RM) that triggers this very odd behavior. In the "limited" DMA mode, it works as expected. Although, the downside is that it automatically stops the ADC when the transfer is done, so that the ADC needs to be restarted after that. But the circular mode behaves very erratically. If anyone's got any idea why...

1 ACCEPTED SOLUTION

Accepted Solutions

Hello, I worked on this some more and finally found out the culprit. So, here are my findings, if it can help anyone. The LPBAM is not trivial on this MCU range and there were no example available of what I was trying to achieve, especially when using LL.

To sum up:

  • Yes, one can enable the AWD and DMA at the same time for ADC4 and that works also fine in Stop 2 mode (as long as you configure clocks appropriately).
  • The "odd" consumption I was witnessing was because the ADC would not be powered down in the particular case I was encountering. (Note that I had enabled the autonomous mode, so auto power off and autonomous DPD.) The reason is the following: if ADC4 has a DMA mode enabled and is being triggered (so a conversion is triggered), but no DMA channel is ready to serve it, ADC4 will just apparently spin in a blocking loop (and thus can't get back to power down). That's not something I was expecting - I had wrongly assumed that if ADC4 had a DMA mode enabled but no DMA was ready to serve it, it would just discard the conversion result and go on. Not so, it just waits. (This also seems to have an odd impact on the Debug IP when going in Stop 2 mode, for a reason I don't understand, but I haven't dug into it further, this part is no big deal, just an oddity.) I ran into this problem because I configured LPTIM1 to trigger ADC4 and so when using a "limited" (one transfer) DMA mode, once the DMA transfer was done, ADC4 would still keep being triggered by LPTIM1 but the DMA channel was then disabled (due to the transfer being complete).

To work around this, I changed my approach:

  • I used the "unlimited" DMA mode for ADC4 and configured LPDMA1 with a linked list to implement a circular buffer, so that conversions can go on until we stop them and the DMA channel is always ready to serve ADC4.
  • I enabled the AWD interrupt and gets the current BNDT value for the DMA channel in the corresponding ISR, to timestamp the AWD events.

Finally, while implementing this approach, I ran into another issue that I also finally figured out:

  • I use SRAM4 to host the LPDMA1 buffer and linked list node(s). But I had forgotten to enable SRAM4's autonomous clock - I guess I had assumed it would be enabled by default, but not so! If not enabled, when in Stop 2 mode, the DMA loading of the next linked list node will fail (it will read all zero's and thus will trigger a "user setting error" for the DMA.

The autonomous clock for SRAM4 is enabled like so:

 

LL_SRDAMR_GRP1_EnableAutonomousClock(LL_SRDAMR_GRP1_PERIPH_SRAM4);

 

 

So there you go. Hope it can help anyone who would run into similar "issues". I'm going to mark this post as "solution", as the issue is fixed and this post explains how.

View solution in original post

4 REPLIES 4
OpusOne
Associate II

I managed to do some more testing with this. The AWD works fine along with the DMA. But. I was able to reproduce the odd behavior described above also in the "limited" DMA mode (DMA one-shot mode, DMACFG = 0).

In DMA one-shot mode, once the DMA transfer is complete, ADC conversions are stopped. This is described, although IMO not clearly at all in the corresponding paragraph in the RM, which states that "The scan sequence is stopped and reset" - what exactly does that mean? Conversions in that case are effectively stopped. But, if one restarts them by setting the CR_ADSTART bit (calling LL_ADC_REG_StartConversion(ADC4)), it does restart conversions, but the ADC gets into this odd state which makes the Debug IP go bonkers and then, the consumption when getting in Stop2 is ~ 40 µA instead of ~ 7 µA. I don't know what's up with that.

Maybe setting the CR_ADSTART bit when a DMA one-shot transfer is complete is not the right thing to do? The register documentation for this bit doesn't mention anything in the particular case of DMA one-shot transfers completed, which DOES stop conversions.

How are we supposed to restart conversions when that happens, if setting the CR_ADSTART is not the right thing to do?

To add to what I tested, if we keep ADC4 in a DMA transfer mode (LIMITED or UNLIMITED) after one successful complete DMA transfer and we restart conversions, this is what causes the odd power consumption afterwards. If we switch the DMA transfer mode to NONE after one first successful DMA transfer, and then restart conversions, it works normally (but obviously with no more DMA). Unless I missed something obvious, looks like I ran into some pretty odd stuff here, because as it is, DMA modes for ADC4 don't look very usable if it only works once. What I haven't tried yet is to reset ADC4 and reconfigure it completely after one DMA transfer (in LIMITED mode), but that doesn't sound very practical.

Any help with this (hopefully) now more precise issue is welcome!

Hello, I worked on this some more and finally found out the culprit. So, here are my findings, if it can help anyone. The LPBAM is not trivial on this MCU range and there were no example available of what I was trying to achieve, especially when using LL.

To sum up:

  • Yes, one can enable the AWD and DMA at the same time for ADC4 and that works also fine in Stop 2 mode (as long as you configure clocks appropriately).
  • The "odd" consumption I was witnessing was because the ADC would not be powered down in the particular case I was encountering. (Note that I had enabled the autonomous mode, so auto power off and autonomous DPD.) The reason is the following: if ADC4 has a DMA mode enabled and is being triggered (so a conversion is triggered), but no DMA channel is ready to serve it, ADC4 will just apparently spin in a blocking loop (and thus can't get back to power down). That's not something I was expecting - I had wrongly assumed that if ADC4 had a DMA mode enabled but no DMA was ready to serve it, it would just discard the conversion result and go on. Not so, it just waits. (This also seems to have an odd impact on the Debug IP when going in Stop 2 mode, for a reason I don't understand, but I haven't dug into it further, this part is no big deal, just an oddity.) I ran into this problem because I configured LPTIM1 to trigger ADC4 and so when using a "limited" (one transfer) DMA mode, once the DMA transfer was done, ADC4 would still keep being triggered by LPTIM1 but the DMA channel was then disabled (due to the transfer being complete).

To work around this, I changed my approach:

  • I used the "unlimited" DMA mode for ADC4 and configured LPDMA1 with a linked list to implement a circular buffer, so that conversions can go on until we stop them and the DMA channel is always ready to serve ADC4.
  • I enabled the AWD interrupt and gets the current BNDT value for the DMA channel in the corresponding ISR, to timestamp the AWD events.

Finally, while implementing this approach, I ran into another issue that I also finally figured out:

  • I use SRAM4 to host the LPDMA1 buffer and linked list node(s). But I had forgotten to enable SRAM4's autonomous clock - I guess I had assumed it would be enabled by default, but not so! If not enabled, when in Stop 2 mode, the DMA loading of the next linked list node will fail (it will read all zero's and thus will trigger a "user setting error" for the DMA.

The autonomous clock for SRAM4 is enabled like so:

 

LL_SRDAMR_GRP1_EnableAutonomousClock(LL_SRDAMR_GRP1_PERIPH_SRAM4);

 

 

So there you go. Hope it can help anyone who would run into similar "issues". I'm going to mark this post as "solution", as the issue is fixed and this post explains how.

Hi OpusOne, thanks for sharing.

I am trying something similar.

I have two cases (Mode STOP1, SRAM4, LPDMA1, ADC4 enabled):

  1. The same as yours: monitor one ADC channel with oversampling and wake up the device on AWD (AWD should be computed on the oversampling accumulation only and not the oversampling result).

  2. Monitor two channels with oversampling and circular DMA in order to get only the latest data when the device is woken up externally (I am trying to use DMA in circular mode to save data in an array of 2 items (one for each channel)).

I am having difficulties running LPBAM. The MCU goes to STOP1 but in the first case, it never wakes up. In the second case, the DMA does the job but only once. I get a correct value for the two channels but only for the first time, as expected, but it seems the ADC is stopped.

Can you share your example with me as a starting point?

Thanks for your help

For 1., make sure you have enabled the interrupt for AWD (1?), including at the NVIC level, otherwise it won't wake up.

This is how I configure AWD1 (in this example, the thresholds are: low = 0, high = 500):

 

LL_ADC_SetAnalogWDMonitChannels(ADC4, LL_ADC_AWD1, LL_ADC_AWD_CHANNEL_1_REG);
LL_ADC_ConfigAnalogWDThresholds(ADC4, LL_ADC_AWD1, 500, 0);
	
LL_ADC_EnableIT_AWD1(ADC4);
LL_ADC_ClearFlag_AWD1(ADC4);

// Interrupts.
NVIC_SetPriority(ADC4_IRQn, 3);
NVIC_EnableIRQ(ADC4_IRQn);

 

Note that the thresholds passed to LL_ADC_ConfigAnalogWDThresholds() are high first, low second, which was confusing to me, so make sure you passed them in the right order if you use LL.

I haven't tried AWD with oversampling using ADC4 yet - maybe there's also something there that isn't quite configured right.