cancel
Showing results for 
Search instead for 
Did you mean: 

DMA on STM32G473 always generates transfer error

Moritz1
Associate III

Hi, Iam using a STM32G473 controller and want to do the following:

I want to output an analog curve, stored in a RAM buffer.
Timer6 is the timebase for transfering the the data from RAM buffer to DAC via DMA.

So I selected the DAC as trigger source for the DMA:

 

DMAMUX1_Channel0->CCR = (DMAMUX1_Channel0->CCR & ~DMAMUX_CxCR_DMAREQ_ID_Msk) | (41 << DMAMUX_CxCR_DMAREQ_ID_Pos); //Select ID 41 (DAC2_CH1)

 

I configured the Timer (using TIM6):

 

//Timer runs with 84 MHz --> auto reload 84 results in Update Event each 1 us (1MHz)
tim.ARR = 84;
tim.CR2 |= TIM_CR2_MMS_1;		//The update event is selected as a trigger output

 

configured the DAC (using DAC2, OUT1):

 

dac.MCR = (dac.MCR & ~DAC_MCR_MODE1_Msk) | (2 << DAC_MCR_MODE1_Pos);		//set channel 1 to mode 2: connected to external pin, without buffer
dac.CR = (dac.CR & ~DAC_CR_TSEL1_Msk) | (7 << DAC_CR_TSEL1_Pos);			//select triggersource 7 for channel 1 as trigger source (=TIM6)

dac.CR |= DAC_CR_TEN1;		//Trigger enabled
dac.CR |= DAC_CR_DMAEN1;	//enable DMA
dac.CR |= DAC_CR_EN1;		//enable Channel 1

 

and finally the DMA (using DMA1, Channel1):

 

dmaChannel.CCR &= ~DMA_CCR_EN;
dmaChannel.CNDTR = 100;		//number of data to transfer
dmaChannel.CPAR = (uint32_t)(&dac.DHR12R1);			//Peripheral address
dmaChannel.CMAR = (uint32_t)buffer;	//Memory address

dmaChannel.CCR |= DMA_CCR_MSIZE_0;				//memory size = 16 Bit
dmaChannel.CCR |= DMA_CCR_PSIZE_0;				//peripheral size = 16 Bit
dmaChannel.CCR |= DMA_CCR_MINC;					//Memory pointer will be incremented
dmaChannel.CCR |= DMA_CCR_DIR;					//Data direction: Memory to peripheral

dmaChannel.CCR |= DMA_CCR_EN;					//enable stream

 

So far everything looks good. In the debugger i see the following adresses:
CPAR1 = 0x50000c08
CMAR1 = 0x20001248

But if I start the Timer with (tim.CR1 |= TIM_CR1_CEN) I immediately get a Transfer error in the DMA channel 1 (TEIF1 in ISR register gets set) and the DMA gets disabled by hardware before any data was transfered (CNDTR remains on 100).

The DAC itselfs is working fine. If I try something like dac.DHR12R1 = 500 I can measure the voltage at the output pin. And also if i do buffer[0] = 99 this works also without any problem.

So Iam 100% shure that both addresses (CPAR and CMAR) are correct and valid.

I do not understand why I get this "transfer error" in the DMA. The reference manual only tells that this occures if you try to read/write from/into an reserved address space. But thats not the case here I think. What else could be the reason for this error?

(timer is running, DAC itself is working, all clocks are enabled)

1 ACCEPTED SOLUTION

Accepted Solutions

Maybe this?

waclawekjan_0-1700815420802.png

But I'm not sure.

Read out and post DMA and DAC registers content at the moment of failure.

JW

View solution in original post

5 REPLIES 5

Maybe this?

waclawekjan_0-1700815420802.png

But I'm not sure.

Read out and post DMA and DAC registers content at the moment of failure.

JW

Moritz1
Associate III

Oh yes, you are right.

I changed the peripheral size in DMA register to 32Bit and now it works! :party_popper:

Thank you so much.

Thanks for letting us know.

I didn't think this would help.

In most STM32, the vast majority of peripherals are behind an AHB-to-APB bridge, and that bridge silently converts "inappropriate" accesses, e.g. "doubles" halfword writes (copies lower halfword to upper halfword) so it probably never signals error on the AHB side.

The 'G4 is weird in that DACs are on AHB, not APB; that might explain that this indeed caused a bus error. I wonder whether attempt to write halfword from processor would throw the processor to fault. Can you please try

*(volatile uint16_t *)&dac.DHR12R1 = 500;

?

JW

The change to 32Bit solved the problem. I have tryed it.

This line of code leads to an error. So it really seems that the 16Bit access was the problem.

Thanks again for the info.

JW