cancel
Showing results for 
Search instead for 
Did you mean: 

Best way to suspend a triple interleaved ADC working in DMA mode 2 And to know the buffer address being written at suspension

MMoha.3
Associate III

Hi,

I've configured the triple ADCs in Interleaved mode with DMA writing the ADC data in circular mode 2 on my Stm32f429 Discovery board.

What I'm trying to implement is:

  1. Initialize DMA and ADCs
  2. Wait for an external interrupt
  3. Pause the DMA transfer
  4. Show the captured waveform on LCD
  5. Resume the DMA transfer, goto step 2

So I wanted to know what is the best way to suspend the ADCs when the external interrupt happens with the HAL functions.

I'm already using this piece of code but I wanted to see if there's a more efficient way:

HAL_ADCEx_MultiModeStop_DMA(&hadc1);
HAL_ADC_Stop(&hadc2);
HAL_ADC_Stop(&hadc3);

Also, I need to know which address in the buffer was being written at the time the interrupt happened.

The AN4031 notes that:

The DMA_SxNDTR register contains the number of remaining data items at the moment when the stream was stopped so that the software can determine how many data items have been transferred before the stream was interrupted.

So I suppose that by using the code below I can find which address of the buffer was being written at the time suspension occurred?

Buffer_Addr_At_Trigger = (Total_Buffer_Length) - (DMA2_Stream0->NDTR);

Thanks in advance.

1 REPLY 1
MMoha.3
Associate III

The NDTR solution that I suggested seems to work.

But I have some trouble for stopping the ADCs,

I first used this code to disable the DMA2 Stream0:

DMA2_Stream0->CR &= ~(1U<<0);

it resets the EN bit of the CR register, So I think it should stop the DMA.

And used this code to re-enable the DMA2 Stream0:

DMA2_Stream0->NDTR = buff_len;    //buff_len being the total buffer length 
DMA2_Stream0->CR |= (1U<<0);

It sets the NDTR value to the total buffer length, and then sets the EN bit of the CR register.

but it cannot re-enable my stream.

So then I used the code I suggested in the question, so in order to disable the DMA2 Stream0:

HAL_ADCEx_MultiModeStop_DMA(&hadc1);
HAL_ADC_Stop(&hadc2);
HAL_ADC_Stop(&hadc3);

and in order to re-enable it:

HAL_ADC_Start(&hadc3);
HAL_ADC_Start(&hadc2);
HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t *)ADC_Buffer, buff_len);

but this one also seems to not restart my stream.

then I used the following lines to restart the stream and it seems to do the job:

MX_DMA_Init();
MX_ADC3_Init();
MX_ADC2_Init();
MX_ADC1_Init();
HAL_ADC_Start(&hadc3);
HAL_ADC_Start(&hadc2);
HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t *)&ADC_Buffer, buff_len);

but then I realized that using this code the ADCs are acting weird and they seem to stop after a few milliseconds, although they are set in circular mode.

Also, another question came up in my mind and that is do I need to stop the ADCs? Or can I just stop the DMA without touching the ADCs?

If anyone has any better approach to suspend/restart the ADCs (or the DMA) I'd be grateful to hear them.