Discovery STM32F429 and DMA DAC on ChibiOS

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

Post Reply
rbarris
Posts: 6
Joined: Tue Feb 11, 2014 8:33 pm

Discovery STM32F429 and DMA DAC on ChibiOS

Post by rbarris »

I have been trawling the forum and read a number of threads about DAC support in ChibiOS on the STM32F4 series. I downloaded a couple of mobyfab's samples but encountered compile errors that I wasn't able to sort out. Before wrestling with it further can I ask if there is a particular sample / branch I should checkout to start from, that's in some kind of known-good state.

Doesn't particularly matter to me if it's in stable branch or somewhere else, just looking for some direction to start with. Any working sample that would show DMA audio out to DAC on the STM32F4 would be helpful.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Discovery STM32F429 and DMA DAC on ChibiOS

Post by Giovanni »

The most finished one should be the one from Mobyfab, I am not sure if he continued the work on it. It is possible the code become not compilable because the changes accumulates over time but it worked at that time.

Giovanni
rbarris
Posts: 6
Joined: Tue Feb 11, 2014 8:33 pm

Re: Discovery STM32F429 and DMA DAC on ChibiOS

Post by rbarris »

I got code checked out from mobyfab's git and got it up and running. But I ran into something weird and it is not clear to me if it's the driver code and the way it approaches DMA, or if it's a hardware bug, or hardware not quite configured right.

For a first test I set up a 1024-sample buffer and 10000 Hz playback. (I had tried 1000Hz playback first, turns out the calculation of the divisor for TIM6 doesn't think about whether the result is going to overflow, which it does when the clock is 84MHz and the target freq is 1KHz, since that's a divisor of 84000 and TIM6 only uses 16bit divisor. No biggie, just stay over about 1282 Hz playback and it works fine ;) )

For the callback, I didn't use any source data buffer or a DMA engine to write samples, I just put in a CPU loop to write ramped values - a global amplitude accumulator that gets incremented by a constant amount with each sample written. Value just wraps as you would expect so the output is just ramps from 0-max and then repeating.

So I get it running, and it's being called with requests for 512 samples each time, as expected. And the dest addresses ('samples' argument) are in bounds for the buffer I set up, at sample 0 or sample 512 base, so this all makes sense. The context as I understand it at this time is that the transfer is "complete" for the section you are about to fill, i.e. no more reads happening there, and that reads will be starting to happen on the alternate section while you are filling the requested section.

What happens on the scope is that periodically, I can see a one-sample glitch in the triangle wave, and the timing of that glitch is that it looks like an echo of a previous sample's amplitude, just delayed by an amount of time that is proportional to the buffer size. Change the buffer size and the distance from that glitch to where that value previously appeared changes with it.

My interpretation is that the DMA, when completing a transfer from either half-buffer section in the circular mode, goes ahead and reads one extra sample that it should not (wrapping around, staying in bounds, but reading from a section of buffer not yet re-generated with data for the current time). I suspect this happens too fast for the ISR to have a chance of putting fresh data in front of it, in fact it may happen before the ISR even triggers.

As an experiment, I changed my callback to write out the 512 samples as asked, but then to predict where the next sample would need to go and the value it would need to have - a 513th sample written. Just had to check for the end of buffer and wrap back to store it in that case. So if the DMA should have finished half-buffer A, and is asking me to refill it, I fill up A and then one sample at the start of B. Later on the opposite will happen and the ISR will be asked to refill section B, I still write all 512 samples there plus one sample at the start of A.

Voila, perfect triangle waves. At 20KHz or 200KHz, looks great.

If I understand this chronology right, the DMA should always be active on the section you are not currently being asked to fill. i.e. you can take your time to write the inactive section, because the DMA engine is currently starting to play the other one.

I think this behavior might be "hiding" in demo DAC code because the wave being played is a sine table being looped and in a way that matches the size of the buffer. Restated I don't think any of the buffer writes in that scenario ever replace an old value with a different value.

Here is some text from the STM32F4 ref manual that got me thinking along these lines:

Section 10.2: Doc ID 018909 Rev 5 299/1705

Direct mode
Each DMA request immediately initiates a transfer from/to the memory. When it is configured in direct mode (FIFO disabled), to transfer data in memory-to- peripheral mode, the DMA preloads only one data from the memory to the internal DMA controller (DMA) FIFO to ensure an immediate data transfer as soon as a DMA request is triggered by a peripheral.


So I am wondering in circular mode, if at the end of a section, where the last sample from that section has been put into the DAC, if one additional sample has been fetched and is now sitting in the FIFO, possibly fetched before its time. The ISR might be working at top speed to refill that location, but the old value has already made it into the FIFO.

BTW this is "non FIFO mode", not 16 sample lookahead or anything like that, just one sample that it wants to fetch.

If this behavior is non negotiable in the hardware, the driver design might need to change to acknowledge it, and ask the app to fill in sections that are offset ahead by one sample.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Discovery STM32F429 and DMA DAC on ChibiOS

Post by Giovanni »

Using those circular buffers (ADC, DAC and soon also SPI and I2S) requires the application to be able to finish working with a buffer half in between callbacks because the DMA never stops.

You have to design your callback code to be able to cope with the data rate you need. The behavior you describe is the expected one if the application fails to fill the half-buffers in time.

Giovanni
rbarris
Posts: 6
Joined: Tue Feb 11, 2014 8:33 pm

Re: Discovery STM32F429 and DMA DAC on ChibiOS

Post by rbarris »

I think it's a little more subtle than that. As it stands the callback has very little code in it, it can start writing data as soon as it gets control.

If the callback is invoked and told to write samples 0-511 - is it your assertion that the DMA engine is, at that moment, already starting to read at sample 0 or sample 512 ? If it's 0, then there is a race built-in. If it's 512, then there's no way my little triangle-wave loop is not fast enough. My interpretation of circular mode is that a section is completed when the DMA engine has picked up the last sample from that range, and that's when the callback is fired up to "refill A while DMA goes over to start reading B" or vice versa.

I guess I could put in more instrumentation and signal ext pins as to which buffer half is being written to and when, and for how long. At 180MHz, I think a tiny for-loop that writes 1KB of data to SRAM (512 16-bit stores) should take well under 100 microseconds ? That's only two samples at 20KSPS (edit for math fail... 50 usec per sample output, 100usec == two samples)

The other bit of data I have backing me up here is that the glitch is always one sample wide. If there was some kind of indeterministic race between callback data production and DMA consumption, I would expect to see a varying width of stale-data glitch from time to time.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Discovery STM32F429 and DMA DAC on ChibiOS

Post by Giovanni »

When a callback is telling you to write 0..511 the DMA is reading 512..1024.

At least this is the intended behavior, the actual implementation may differ.

Giovanni
rbarris
Posts: 6
Joined: Tue Feb 11, 2014 8:33 pm

Re: Discovery STM32F429 and DMA DAC on ChibiOS

Post by rbarris »

Giovanni wrote:When a callback is telling you to write 0..511 the DMA is reading 512..1024.

At least this is the intended behavior, the actual implementation may differ.

Giovanni


That matches my expectation. In that scenario, using a 1024-sample total buffer being played back at 20KHz, each half is playing for about 2.5ms, which should be far more than enough time for a simple loop to fill the non-playing half. I'll see if I can clean this up and turn it into an example that makes the behavior more clear.
mobyfab
Posts: 484
Joined: Sat Nov 19, 2011 6:47 pm
Has thanked: 21 times
Been thanked: 31 times

Re: Discovery STM32F429 and DMA DAC on ChibiOS

Post by mobyfab »

Hey Rob,

I Got your email,

Let me know if you need any help with that.

The current dac-new branch was a couple month behind current master, I merged and pushed the changes.
rbarris
Posts: 6
Joined: Tue Feb 11, 2014 8:33 pm

Re: Discovery STM32F429 and DMA DAC on ChibiOS

Post by rbarris »

Thanks for dropping in. OK so which branch should I pull to get latest combination ?
mobyfab
Posts: 484
Joined: Sat Nov 19, 2011 6:47 pm
Has thanked: 21 times
Been thanked: 31 times

Re: Discovery STM32F429 and DMA DAC on ChibiOS

Post by mobyfab »

rbarris wrote:Thanks for dropping in. OK so which branch should I pull to get latest combination ?


This one: https://github.com/mobyfab/ChibiOS/tree/dac-new
Post Reply