DMA losing sync on ST ARM processor

I'm using an STM32F103VB, and one of the things that I'm doing is doing a set of ADC reads which are then being transferred via DMA to a buffer.

For some reason, when I'm debugging the DMA transfer gets scrambled: channel 0 ends up where channel 1 is supposed to go, channel 1 where channel 2 should be, on up the line until finally the last channel gets written to channel 0.

I have the code set up for the ADC to run in "scan" mode, with the DMA (theoretically!) sucking the data off and putting it into memory.

Furthermore, I have the ADC ISR set up so that on an end of conversion interrupt (which is only supposed to happen at the end of the scan in scan mode) the DMA engine gets reinitialized to point to the base of the memory array it's supposed to write to.

Does anyone have any obvious clue to what I'm doing wrong? Does ST have any good bits of sample code that I've missed?

Thanks in advance.

--
My liberal friends think I'm a conservative kook.
My conservative friends think I'm a liberal kook.
 Click to see the full signature
Reply to
Tim Wescott
Loading thread data ...

Whoops -- I meant to cross-post this to sed, 'cause there may be folks over there with useful information, too.

--
My liberal friends think I'm a conservative kook.
My conservative friends think I'm a liberal kook.
 Click to see the full signature
Reply to
Tim Wescott

.
e

ave

a suggestion from a quick google

formatting link
z1yLmVUCe5

-Lasse

Reply to
langwadt

e

ttdesign.com

Do you have the DMA set up to operate in circular mode? If so then it sounds like the DMA is doing one transfer before the first ADC conversion is complete. Try changing your ISR to only set up the DMA but not start the ADC and see if the DMA counter drops by one as soon as you exit the ISR.

Also remember that the ADC has two interrupt sources, one for EOC and one for JEOC so make sure you're using the right one.

If this ONLY happens while debugging through JTAG then it may be that your debugger halts the DMA but not the ADC. Some peripherals like the CAN controller can be selected to either keep running or halt during debug.

Reply to
peter_gotkatov

#axzz1yLmVUCe5

That's way too simple -- my problem isn't getting the right numbers out of the ADC. My problem is getting the right numbers out of the ADC, at the right times, and into the right spots in memory fast.

The _only_ way that I can see to do multiple consecutive ADC conversions with that part is to use the ADC scan mode and DMA -- so I pretty much must get it working.

It is very frustrating to halt the processor, restart, and see all the right numbers in all the wrong places. Scary, too, considering that I'm controlling enough power to make things awfully toasty if I screw it up.

--
My liberal friends think I'm a conservative kook.
My conservative friends think I'm a liberal kook.
 Click to see the full signature
Reply to
Tim Wescott

Initially I had it set up with the DMA in circular mode, and the interrupt coming from the DMA controller on the completion of a set of writes. That gave me this problem as soon as the processor started, so I axed that pretty quick!

Hmm. I'll try that, but it really shouldn't be doing so.

Currently the DMA is set to terminate at the end of a transfer, and to start it up again you need to disable the DMA, re-initialize the length register, then turn it on again.

It does make me think that carefully checking the order in which I turn things back on may bear fruit. However, the way that the whole system is set up (and if I understand ST's documentation), the ADC gets triggered periodically from a timer, converts a bunch of channels which get squirreled away in memory by the DMA, then interrupts.

So if the DMA is getting set up in the interval when the ADC is quiescent, even if it gets screwed up once when the processor starts up, it should still get back on track the next ISR -- or, at least that's how I read things. Yet this is obviously not the case.

I'm only interrupting on EOC.

Good thought, I'll think about implications, and how to test.

--
My liberal friends think I'm a conservative kook.
My conservative friends think I'm a liberal kook.
 Click to see the full signature
Reply to
Tim Wescott

.
T
m

should have mentioned I was looking at the post by "tony" two thirds down the page, look like scan of two channels with dma

-Lasse

Reply to
langwadt

Here's how I've been doing it on an STM32F103RB. ADCStart() is called from the main loop to kick things off. DMADone and ADCActive are extern volatile so that main can keep an eye on progress. Mind the line wrap on some of the comments.

--
// We'll get ADC_NUM_CHANS results in sequence and use DMA to save the
// results of the conversions to the output array. No ADC IRQ is needed;
 Click to see the full signature
Reply to
Rich Webb

As long as ADC_SR_EOC is clear before you set DMA_CCR1_EN then there should be no problem. I don't know if JEOC needs to be cleared as well but it wouldn't hurt.

Reply to
peter_gotkatov

I think the STM32 debug hardware has the option to stop the timer clocks when debugging. If you don't do that, perhaps your timer is triggering an ADC cycle while in the debug mode.

Mark Borgerson

Reply to
Mark Borgerson

to

d:

re

ry.

of

to

ks

/

at

s

I'm

.

generally when you are working on stuff that controls with motors and power stopping the cpu is not an option. You have to use some type of realtime debugger to look at variables and such

used to be that you had to make your own with uart or something like that, but now most also have to the option to do it over the jtag or what ever debug interface is used

-Lasse

Reply to
langwadt

The manual for the STM32F2xx mentions that the option to keep the timer clocks running when the CPU is halted for debugging is useful when using the timers to generate PWM for motor control.

Mark Borgerson

Reply to
Mark Borgerson

memory.

depends on how intelligent the timer is of course, but imagine a robot controlled by that motor, stop the cpu at the wrong time at it might just keep going until it hits something HARD

-Lasse

Reply to
langwadt

to

scrambled:

where

memory.

of

to

folks

conversions

up.

That kind of problem is always present when controlling motors and other mechanical systems. Real-Time debugging is difficult even with the best of hardware. That's one reason I've never been particularly interested in writing code for computer-controlled sawmills!

When I was working on autonomous aerial vehicle code, there were two kinds of debugging----offline PC sims to debug algorithms, and the "record everything and analyze after the crash" for the hardware- associated problems. (The 'crash' was usually not a computer reset type crash. It was an "I was flying and now I'm not" type of crash.)

Mark Borgerson

Reply to
Mark Borgerson

stm32/

It looks like he's doing what I'm trying; maybe he didn't debug.

At any rate, I found a horrible kludge that seems to work. At the end of the ISR, I reset the DMA controller leaving room for the ADC channels _plus one_. I'm sure that when I die and I'm trying to convince St. Peter that I belong up instead of down, that this kludge will be raised as a topic of conversation:

DMA.CHAN_1.CCR.bits.EN = 0; // disable DMA DMA.CHAN_1.CMAR = raw_adc_readings; // set address DMA.CHAN_1.CNDTR.bits.NDT = ADC_CHANNELS + 1; // Number of ADC channels + kludge DMA.IFCR.bits.TCF1 = 1; // Clear the transfer complete interrupt DMA.CHAN_1.CCR.bits.EN = 1; // enable DMA

ADC1.SR.bits.EOC = 0; // clear interrupt

--
My liberal friends think I'm a conservative kook.
My conservative friends think I'm a liberal kook.
 Click to see the full signature
Reply to
Tim Wescott

e
s
t

at

so it is only when you debug? what are you using for debug?

of

I've seen worse but, are you setting the dma up for circular mode? if you do that and have the plus one aren't you pretty sure it will go wrong if you are ever late with the interrupt?

guess you could put a magic number at that extra location and if it ever gets overwritten panic or what ever makes most sense :P

-Lasse

Reply to
langwadt

JTAG, OpenOCD and gdb for debugging.

The DMA is _not_ in circular mode.

I may monitor the extra location -- but I suspect that I'll just find out that it stays zero until after I halt and restart.

--
Tim Wescott
Control system and signal processing consulting
 Click to see the full signature
Reply to
Tim Wescott

,
d
e

he

o

ng

I

nd

r

did you have that before?

it should tell you something about whether it is the dma or the adc that gets confused

-Lasse

Reply to
langwadt

Il 20/06/2012 17:51, Tim Wescott ha scritto:

Maybe you left a dma or adc memory watch opened? Reading a register can trigger some event, and it will be triggered even if you left a dma or adc regs watch opened.

L
Reply to
Sacchi

I just got an email on this asking how I resolved it -- so I guess I should revive this dusty old thread and answer my own question.

I can't be entirely sure with the passage of time, but I believe that this is the pertinent bit of code, found in my ADC ISR:

DMA.CHAN_1.CCR.bits.EN = 0; // disable DMA DMA.CHAN_1.CMAR = raw_adc_readings; // set address DMA.CHAN_1.CNDTR.bits.NDT = ADC_CHANNELS + 1; // Number of ADC channels + kludge DMA.CHAN_1.CCR.bits.EN = 1; // enable DMA

This ISR triggers off of the ADC end-of-conversion, _not_ the DMA: I don't know if that's necessary to the fix, or if it just happened to make things work. I'm pretty sure (I certainly hope!) that this end-of-conversion interrupt happens at the end of the sequence -- the reader should check his documentation to make sure.

The pertinent setup (well, some -- there's a bazillion bits to set) is:

ADC1.CR1.bits.EOCIE = 1; // interrupt on conversion end ADC1.CR1.bits.SCAN = 1; // scan ADC1.CR2.bits.DMA = 1; // use DMA ADC1.CR2.bits.ALIGN = 1; // left alignment ADC1.CR2.bits.EXTSEL = 0x04; // Trigger on Timer 3 TRGO event.

--
Tim Wescott 
http://www.wescottdesign.com 
 Click to see the full signature
Reply to
Tim Wescott

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.