cancel
Showing results for 
Search instead for 
Did you mean: 

How to get ADC-DMA working on a STM32G431KB board with CubeIDE

HWhit.1
Associate III

Hi,

I am using a STM32G431KB board with STMCubeIDE. I am trying to read out the one ADC using DMA but have run into problems. As I am new to the STM32G4 and STM STMCubeIDE. I decided to follow the example of Shawn Hymel https://www.youtube.com/watch?v=EsZLgqhqfO0. A number of other examples are available which are essentially the same.

I got the single conversion example working correctly. This tells me the ADC is working.

The ADC-DMA example did not work and despite several weeks of investigation I am unable to find the reason for this. I have attached the key parts of the main code. This sets up the ADC and immediately before calling HAL_ADC_Start_DMA writes a constant value of 2047 to the ADC buffer. Once started the buffer is read out to the UART where the conversion values (albeit without sync) are written.

What I can deduce from this code is:

1. Zeros are being written to the ADC buffer by the DMA instead of the ADC conversion value. (The debugger shows that the “2047�?s are overwritten with zeros).

2. The buffer half-complete and buffer complete interrupts are being called.

3. The timing of the digital toggle on GPIO pin 10 is consistent with a ADC clock of 170/4 MHz, suggesting the clocks are set correctly.

Other tests revealed:

4. HAL_ADC_Start_DMA does not return an error code.

5. Reading the forum it seems the capacitor switching can lead to the ADC conversion becoming frail at too high a clock frequency. So I tried changing the clock pre-scaler from divide by 4 to divide by 6. This gave no improvement.

Incidentally, I did try to import the code to the Arduino IDE. That did not work either.

If anybody has any idea what is wrong, or where to look. Please let me know.

Many thanks in advance.

volatile uint16_t adc_buf[ADC_BUF_LEN];
char msg [20];
int16_t ix;
 
 
int main(void)
{
  HAL_Init();
 
  for (int i = 0;i < ADC_BUF_LEN; i++){
	  adc_buf[i] = 2047;
  }
 
 
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, ADC_BUF_LEN);
  sprintf(msg, "Started ADC \r\n");
    HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
    HAL_Delay(1);
 
  while (1)
  {
	  for (int i = 0; i < ADC_BUF_LEN; i++ ){
		  sprintf(msg, "%i : %hu\r\n",i, adc_buf[i]);
		  HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
		  HAL_Delay(1);
	  }
 
  
 
 
 
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc1){
	  // Test_set GPIO pin High
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
 
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc2){
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
}
 

9 REPLIES 9

Read the ADC/DMAMUX/DMA chapters in RM. Read out and check/post the ADC/DMAMUX/DMA/relevant GPIO registers content.

You may want to start with a polled ADC implementation, and then proceed to DMA.

JW

HWhit.1
Associate III

Hi,

I have (i) started with a polled implementation and recorded the ADC registers, (ii) Implemented the ADC/DMA code Read out using the STM32CubeIDE debugger the registers.

(I) The polled ADC readout works.

(ii) The ADC/DMA/DMAMUX code does not work. The ADC DR register is stuck on zero. I have ascertained that the DMA is reading these zeros because if I populate the ADC buffer with some numbers, these are written over with zeros.

So the problem seems to be with the ADC and not the DMA. Reading the chapters in the manual the register values all seem OK. The only think I can think of is that the ADSTART bit in ADC_CR is not set. This should be 1 if the ADC is operating. I begin to think this can be a problem at the hardware level.

The non-zero register values and IDs for the non-zero bits are listed below.

Best regards,

H.

....Polling conversion WORKS

ADC1

ISR: 0x3 ESOP + ADRDY

CR: 0x10000001 adregen + ADEN

CFGR:0x80000000 JQDIS

TR1: 0xfff0000 HT1 (FFF)

TR2: 0xfff0000 HT2 (FFF)

TR2: 0xfff0000 HT3 (FFF)

SQR1: 0x40 SQ1

DR: 0x734  (changes)

....DMA conversion DOES NOT WORK

ADC1

ISR: 0xb EOS EOSMP ADRDY

IER: 0x3c0 OVRIE

CR: 0x10000001 ADVREGEN ADEN

CFGR: 0x80002003 JQDIS CONT DMACFG DMAEN

TR1: 0xfff0000 HT1 (FFF)

TR2: 0xfff0000 HT2 (FFF)

TR2: 0xfff0000 HT3 (FFF)

SQR1: 0x40 SQ1

DR: 0x0 (Does not change)

DMA1

ISR: 0x3 TCIF1 GIF1

CCR1: 0x5af EN TCIE HTIE TEIE MINC PSIZE MSIZE

CNDTR1: 0x1000  NTD = 0x1000

CPAR1: 0x50000040 PA = 0x50000040

CMAR1: 0x20000178 MA = 0x20000178

DMAMUX

C0CR: 0x5 DMAREQ_ID = 0x5

HWhit.1
Associate III

I have imnvestogated this further by looking at the ADC registers using debug. I come to the following:

  1. Using a simple polling routine it clearly works in single conversion mode. Adapting this to continious conversion mode, the ADC data registerdoes not update the output register. The implication is thai if DMA is working the adc buffer will be filled with zeros. Which is what is observed.
  2. Reading the manual extensively I did not find an explanation for this.
  3. For another chip there is a note about updating the ADC data register in an errata. This could explain why and as it need programatic intervention after every read of the data buffer it is not possible to test with DMA.
  4. I checked the code with a nucleo- STM32L476RG board and the ADC-DMA code worked as intended. So the problem is associated with the STM32G431KB board.

I therefore seems to me the STM32G431KB board cannot be used with HAL and STMCubeIDE to read ADC1 via DMA (at least easily). The idea of HAL in the IDE is that it should facilitate simple and implementation of peripheral functions. I have had to spent about 2 months trying to find the problem, which hardly makes implementation of my project efficent.

MJand.1
Associate

I have a same problem. Can someone tell us what is wrong it G4 series? (I am using STM32G474, and even simple polling routine doesn't work clearly and seems to be extremly time dependent.) 

OMarq.1
Associate II

Hello,

I'm also stuck with the same problem. DMA does not write to the buffer as requested and it is filled as default with 0s (zeros) only. Single conversion without DMA works fine. It is not just the G4 series.

But stranger is that it used to work. I followed the mentioned tutorial: https://www.youtube.com/watch?v=EsZLgqhqfO0 with Nucleo board STM32L4P5ZG and it worked fine last year (2021). I now need the same code and behavior that worked correctly before and now it just doesn't work anymore. I can just assume that there is an issue with an unsolicited update of STM32Cube IDE. I think I will need to set up the memory address for DMA manually now. I look forward to learning how to do this.

If anyone have found the solution for this problem, it would be great if he/she shares the experience.

JFran.13
Associate

I'm having the same issue on a custom board with an STM32G030F6P.

HWhit.1
Associate III

Hi,

I did not find a solution to the case with continuous repetitive ADC readout and DMA.

However, for another application using a STM32G431, I have successfully used TIM15 with 170 MHz clock frequency and a divide (synchronous) by 64 counter to trigger single ADC 12-bit conversions with DMA at close to maximum at 2.66 MS/s with what seems to be perfect synchronization. The fADC clock was (synchronous) 170/4 (synchronous) = 42.5 MHz. The theoretical maximum sample rate at this fADC is 2.83 MS/s for 12 bit conversions.

So, the best advice I can currently give is to use a timer to trigger the ADC at precise regular intervals. Moreover, I recommend synchronous division of the bus clock for fADC. This facilitates precise synchronization between the ADC trigger clock (TIM15 in my case) and ADC clock which gives exact sampling intervals.

My current thoughts are that as continuous polling with DMA take place at intervals that are determined (at least to some degree) by bus usage. As the bus latency can vary, the ADC sampling will not be exactly at the same time interval. These variations can be a problem as most signal processing algorithms require regular sampling intervals, or somehow, you know the exact sampling times. So maybe I was just not being very smart in my original project....

Best regards,

H.J. Whitlow

.

samuel23
Associate III

Hi,

Sorry to re-up this old subject... But it seems to match an issue I have... and it can be better than reopen a new one.

 

In our case, with G431KB (+cubeide last version 1.15):

- TIM6 triggers ADC2 (Both interrupts TIM6+ADC2 confirm that ADC do the job each time TIM6 overflow)

- We want DMA1 CH1 to be triggered by every acquition of ADC. But, we measured the period of DMA interrupts... and it is much faster than ADC acquisition!!!!!!!

- in some case, it happens (not randomly) that DMA copied a right value from ADC (sometime exactly every 21 seconds !!)

 

We just suspect that DMA is triggered by a bad signal... 

But, when we disable the ADC, the DMA is not trigger anymore... that means it was "not so bad".

 

Any idea?

Any example of working TIM+ADC+DMA to help us?

Thanks!!!

I found my mistakes...

If you read this post beacause you met similar issue, your problem is certainly different...but I suggest you to check your "ranks" in the config of channels.

With G4, the ranks are not as simple as on STM32F1 family.... ! (0->6->12->18->24->and more crazy after instead of 0->1->2->3....)

Anyway, I got a software which correctly read in a circular way a list of channels, triggered with TIM6, and "DMA writing" values in an array!

've fun