View previous topic :: View next topic |
Author |
Message |
Meister
Joined: 27 May 2010 Posts: 319
|
Posted: Tue Jul 28, 2015 10:37 am Post subject: Xmega: What are Config DMA and Config ADC are doing? |
|
|
In my project (Xmega)
http://www.mcselec.com/index2.php?option=com_forum&Itemid=59&page=viewtopic&t=12965
I am doing DMA transfers from the freerunning ADC repeatedly.
However, to keep this running - and not just once as in the Mak3's examples - I have to reconfigure the DMA and the ADC each time after the Do.... within the Loop.
Code: | Do
Config Dmach0 = Enabled , Burstlen = 2 , Chanrpt = Disabled , Tci = Lo , Eil = Lo , Singleshot = Disabled , _
Sar = Burst , Sam = Inc , Dar = None , Dam = Inc , Trigger = &H10 , Btc = 4000 , Repeat = 1 , Sadr = Varptr(adca_ch0_res) , Dadr = Varptr(samples(1))
Config Adca = Free , Convmode = Signed , Resolution = 12bit , Dma = Ch01 , _
Reference = Int1v , Prescaler = 8 , Sweep = Ch0 , Event_mode = None , Event_channel = Ch0123 , _
Ch0_gain = 1 , Ch0_inp = Single_ended , Mux0 = &B00000000
....
Loop |
I assume using register settings would be slightly faster than using Configs repeatedly.
I tried to find out with help of ICE which registers are being set, but I must have missed some settings.
Could somebody (Mark? ) tell which registers are being set by those Configs?
I am asking this here rather mailing to support since it might be of more general interest.
Regards, Meister
(BASCOM-AVR version : 2079 , Latest : 2.0.7.8 ) |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Jul 28, 2015 3:41 pm Post subject: Re: Xmega: What are Config DMA and Config ADC are doing? |
|
|
Meister wrote: | I tried to find out with help of ICE which registers are being set, but I must have missed some settings. |
Why do you use JTagICE, even AVR-Studio 4 can do it via software, load the Bascom obj-file, open up a disassembler window on the config-line and look up the register values which are stored via STS, sure you have to translate the absolute addresses into the appropriate register names, but even there AVR-Studio will help you.
Quote: | I am asking this here rather mailing to support since it might be of more general interest. |
I thought support is for bugs and updates and not for sparing users to read the data sheet.
Quote: | I assume using register settings would be slightly faster than using Configs repeatedly. |
The config is a few LDI/OR/AND/STS opcodes and I doubt if will be faster, if you do the same.
However, there's no need to configure everything from new, the DMA does not clear all of it's configuration data.
I noticed from the linked thread, that you've complained about the array not being written at following runs, you seem not to have fixed that issue, as you still have Dar = None in your code, which, for a proper reload of the destination address has to be BLOCK or TRANSACTION, either of them works, as long block repeat is 1.
The reason, why your manual configuration does not work, is because you forgot to set TRFCNT and REPCNT, which are decremented by the DMA-controller.
If setting these registers is done, together with Dar = BLOCK, then it should suffice to enable the DMA-transfer by setting CtrlA.CHEN, it is started then by the still active ADC trigger source. |
|
Back to top |
|
|
Meister
Joined: 27 May 2010 Posts: 319
|
Posted: Tue Jul 28, 2015 4:19 pm Post subject: |
|
|
Hi MWS,
thanks for your comments.
Quote: | The config is a few LDI/OR/AND/STS opcodes and I doubt if will be faster, if you do the same. |
So for the time being I will keep it like that for the sake of having less trouble...
Meanwhile I am having a nice averaging triggered oscilloscope on the Xplained LCD.
Considering the linked code:
Quote: | you've complained about the array not being written at following runs, you seem not to have fixed that issue, |
No, that was fixed by using the reoccuring Config statements. The code works flawlessly repeatedly. That was the reason why I had posted it, after long time of experimenting.
What is a little bit unexpected: I don't need to wait for Bitwait Dma_ch0_ctrlb.4 , Set
Maybe the DMA transfer is that fast that the following Max(...) in the linked code never encounters an incompletly filled array. |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Jul 28, 2015 5:17 pm Post subject: |
|
|
Meister wrote: | So for the time being I will keep it like that for the sake of having less trouble... |
Hmm, if you don't want to learn, I wonder why you ask then and create a topic?
Quote: | No, that was fixed by using the reoccuring Config statements. The code works flawlessly repeatedly. |
Again, if you're happy with what you got by trial and error, I miss the knack why you ask here, or why I (or anyone else) should take the efforts to think about your problems.
Quote: | What is a little bit unexpected: I don't need to wait for Bitwait Dma_ch0_ctrlb.4 , Set
Maybe the DMA transfer is that fast that the following Max(...) in the linked code never encounters an incompletly filled array. |
DMA needs to wait for the ADC, so it won't fill up faster than the ADC can sample.
Your code is flawed, the first time it may work ok, the following samples are random, as you never clear this TRNIF-flag, so Bitwait Dma_ch0_ctrlb.4 , Set subsequently don't work, as it's always true.
You may get results, but you don't get results the way you think
And yes, you would be far better off, if you'd read the XMega's data sheet and appnotes, instead of wasting time by this kind of random programming. |
|
Back to top |
|
|
Meister
Joined: 27 May 2010 Posts: 319
|
Posted: Tue Jul 28, 2015 7:49 pm Post subject: |
|
|
Hi,
Quote: | the first time it may work ok, the following samples are random |
Not true. If I change the incoming waveform when the program is running, the output on the GLCD "instantly" reflects the input after having summed up 256 DMA transfers.
If just the first one were right, its signature should vanish in the result.
There are two Transaction Complete Interrupt Flags, one for the DMA, one for the channel, but I can't see which one would be relevant (anyway it looks like none is needed to be interrogated).
Bitwaiting for either of these after the Config statements like this (there is nothing more dealing with the DMA or ADC settings between Do and Loop)
Code: | Do
Config Dmach0 = Enabled , Burstlen = 2 , Chanrpt = Disabled , Tci = Lo , Eil = Lo , Singleshot = Disabled , _
Sar = Burst , Sam = Inc , Dar = None , Dam = Inc , Trigger = &H10 , Btc = 4000 , Repeat = 1 , Sadr = Varptr(adca_ch0_res) , Dadr = Varptr(samples(1))
Config Adca = Free , Convmode = Signed , Resolution = 12bit , Dma = Ch01 , _
Reference = Int1v , Prescaler = 8 , Sweep = Ch0 , Event_mode = None , Event_channel = Ch0123 , _
Ch0_gain = 1 , Ch0_inp = Single_ended , Mux0 = &B00000000
Bitwait Dma_ch0_ctrlb.4 , Set ' alternatively Bitwait Dma_intflags.0 , Set
Set Dma_ch0_ctrlb.4 ' Set Dma_intflags.0
...
Loop |
does not have any visible effect on the sampled waveform.
Since the samples are well defined rather than random, is there some explanation? |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Jul 28, 2015 8:42 pm Post subject: |
|
|
Meister wrote: | Since the samples are well defined rather than random, is there some explanation? |
I wrote:
Quote: | You may get results, but you don't get results the way you think |
"Randomly" describes that you actually get data, but not the one you expect.
Assume 4 clocks per conversion, prescaler 8 and 4000 samples = 128000 clocks. That's nothing for an uC running 32Mcycles, but far too much for the max, as your code runs straight over the bitwait.
This way the max-function has no chance to get valid data from the current sample run. But - you waste some more time, print, waitms, a.s.o. That's time for the DMA to fill up the sample-array, means the next call for max will work on previously fetched data. This way it collects data, only not the way and in the exact period the guy in front of the machine has intended it |
|
Back to top |
|
|
Meister
Joined: 27 May 2010 Posts: 319
|
Posted: Wed Jul 29, 2015 10:04 am Post subject: |
|
|
Maybe the Bitwait misses the Transaction complete flag.
Maybe that was the reason for Mak3 in his DMA examples to introduce a variable Dma_ready that was set by interrupt and interrogated in Do ... Loop until Dma_ready=1.
I was not able to get this running repeatedly, despite spending a lot of time, so I came up with that what you are criticising.
(This applies to all Mak3's DMA examples -including DMA-UART (it prints just once) which otherwise are nice).
I think a better way compared to using the interrupt would be to have kind of StART DMA modified that it starts the DMA transfer and waits for the transaction to be complete.
Would you mind to help with this? |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Wed Jul 29, 2015 12:13 pm Post subject: |
|
|
Meister wrote: | Maybe the Bitwait misses the Transaction complete flag. |
I do not think it gets missed, but as you have a repeating signal, you won't notice the difference about the previous or the actual sample of the signal.
And that's all the difference bitwait makes.
And btw., if you wait in a loop for completing the DMA, you miss the benefit of DMA.
DMA is useful to do things in the background, without wasting otherwise valuable processor time, if you do a bitwait this is your clock-wasting loop.
If you do sampling and filling the ADC instead of DMA with a loop, and assumed each loop-run does not take more time than the period between ADC-samples, you have the same result in regards of efficiency.
What I was pointing out is, that a) your code works, only not as intended, and b) you have to make sure, that your data is consistent.
I do not believe you want to have data, that is mixed up out of two not connected periods, and use the max-function thereon.
Assumed you don't use bitwait, or don't clear TRNIF, here's how your code works:
- ADC is constantly sampling, each sample takes in your case 40 processor cycles, 5 (not the 4 previously assumed) for 8bit and prescaler 8.
- DMA is started
- Depending on the progress of the ADC the trigger occurs in 0 to 40 cycles
- assuming the ADC triggers DMA instantly, the first result is pushed within a few cycles into the sample array
- max-function is started, it takes a few cycles to prepare and then, let's say 10 cycles for each iteration through the array
- if preparation for max takes more than 40 cycles, the second cell of the sample array is filled
- max iteration happens and now max runs ahead of the sampling, as it is iterating faster than the DMA can fill up the array
- max does this way calculation based to a tiny amount on actual and in a bigger amount on previous data
If max would take more than 40 cycles for each iteration, then the ADC would run ahead.
I can not imagine, that you want to build code and don't know what you're actually calculating.
Quote: | Maybe that was the reason for Mak3 in his DMA examples to introduce a variable Dma_ready that was set by interrupt and interrogated in Do ... Loop until Dma_ready=1. |
Set a link to his code.
Quote: | I was not able to get this running repeatedly, despite spending a lot of time, so I came up with that what you are criticising. |
As said I've pointed out what you think in contrary to what the code actually does.
Quote: | I think a better way compared to using the interrupt would be to have kind of StART DMA modified that it starts the DMA transfer and waits for the transaction to be complete. |
I would start the transfer, while the processor does useful other things, like pushing out data to a display.
If a delay between calculation and sampling is acceptable, I'd do it this way:
- loop start
- max calculation
- start DMA
- print ... or/and wait some
- loop end
The first max is void this way, the subsequent max's are always calculations of previous data, but as long as print and wait uses up more than 160000 cycles, there won't be inconsistent data.
Otherwise one could think on sampling continuously and copy chunks, or all of the data to work with into a second buffer. Needs an ISR to reload TRFCNT and extra SRam. |
|
Back to top |
|
|
Meister
Joined: 27 May 2010 Posts: 319
|
Posted: Wed Jul 29, 2015 2:14 pm Post subject: |
|
|
Quote: | Set a link to his code. |
http://bascomforum.de/
At present I need a 600us Wait between the trigger pulse and the start od the DMA to catch the right part of the signal. Of course, this slows down the whole thing (256x0.6ms=0.15s, the whole repetition rate is ~<1s). I tried as you suggested to reorder the code, but even when putting all the GLCD stuff on top I need this delay (even somewhat more). I am now preparing to replace that by a hardware delay using an Tiny85 between the trigger signal and the Xmega, so I hope to get rid of the 600us Wait, but I am not sure if there won't be a surprise... I think the Cmemwcpy code was provided by some MWS....
Quote: | or all of the data to work with into a second buffer. |
Yes, I was considering this. If the Config DMA would have an option on that, I would have tried it already. So one has to work with the registers.
This is how it looks so far:
Code: | Do
Cmemwcpy Samples(1) , Summ(1) , Sample_count
Bitwait Pinb.0 , Set 'Wait for Triggerpulse
Toggle Portr.0
Waitus 600 'Sampling Delay
Config Dmach0 = Enabled , Burstlen = 2 , Chanrpt = Disabled , Tci = Lo , Eil = Lo , Singleshot = Disabled , _
Sar = Burst , Sam = Inc , Dar = None , Dam = Inc , Trigger = &H10 , Btc = 4000 , Repeat = 1 , Sadr = Varptr(adca_ch0_res) , Dadr = Varptr(samples(1))
Config Adca = Free , Convmode = Signed , Resolution = 12bit , Dma = Ch01 , _
Reference = Int1v , Prescaler = 8 , Sweep = Ch0 , Event_mode = None , Event_channel = Ch0123 , _
Ch0_gain = 1 , Ch0_inp = Single_ended , Mux0 = &B00000000
'Bitwait Dma_ch0_ctrlb.4 , Set 'No change when enabling
'Set Dma_ch0_ctrlb.4
'Bitwait Dma_intflags.0 , Set '
Stp = 1
K = K + 1
L = K Mod 256
If L = 0 Then
Idxmin = 1990 : Idxmax = Idxmin
Minn = Get_min_sint_16(summ(2) , Idxmin )
Maxx = Get_max_sint_16(summ(2) , Idxmax )
Idxmin1 = Idxmin + 2 : Idxmax1 = Idxmax + 2
For I = 16 To 2000 Step 16 'Compress data
Idx = I
Shift Idx , Right , 4
Temp = 0
Temp = Sum(summ(i) , 16)
Shift Temp , Right , 4 , Signed
Summ(idx) = Temp
Next
Idxmin = 124 : Idxmax = Idxmin
Minn = Get_min_sint_16(summ(2) , Idxmin )
Maxx = Get_max_sint_16(summ(2) , Idxmax )
Idxmin = Idxmin + 2 : Idxmax = Idxmax + 2
Print #1 , Idxmin ; "Minn=" ; Minn ; " ;" ; Idxmax ; " " ; Maxx
C3 = Maxx - Minn 'Normalizing for GLCD
C1 = C11 / C3
C2 = Servomin * Maxx
C21 = Servomax * Minn
C2 = C2 - C21
C2 = C2 / C3
Call Lcd_clear(white)
For I = 10 To 125
Temp4 = Summ(i)
Temp4 = Temp4 * C1
Y = Temp4 + C2
I2 = I
Call Lcd_set_pixel(i2 , Y , Black)
Next
I2 = Memcopy(null , Summ(1) , 4000 , 2) 'Clear array to avoid to be fooled if the array were not updated.
Text11 = Str(maxx)
Text11 = Format(text11 , "0000")
Call Lcd_text(text11 , 0 , 1 , 1) 'Draw Text to Buffer
Text11 = Str(minn)
Text11 = Format(text11 , "0000")
Call Lcd_text(text11 , 0 , 25 , 1) 'Draw Text to Buffer
Text11 = Str(idxmin1)
Text11 = Format(text11 , "0000")
Call Lcd_text(text11 , 90 , 25 , 1) 'Draw Text to Buffer
Text11 = Str(idxmax1)
Text11 = Format(text11 , "0000")
Call Lcd_text(text11 , 90 , 1 , 1) 'Draw Text to Buffer
Call Lcd_show()
End If
Loop |
|
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Wed Jul 29, 2015 9:47 pm Post subject: |
|
|
Meister wrote: | (256x0.6ms=0.15s, the whole repetition rate is ~<1s) |
Where does the 256 come from? Calculation and display is done for only one of it, the other 255 samples are processed in different code then?
I would feel it helpful, if the purpose is described, together with signal form and timing.
Thought about steadily sampling and picking out the right data, but it depends on given requirements.
An external interrupt and timer can be used for the 600µs delay, start and end of sample, as then end of the block does not equal the sample end.
But you mentioned somewhere not to use interrupts. This approach, which would be non-blocking, needs to make use of them.
You can try out, this config should continuously sample into the array:
Code: | Config Dmach0 = Enabled , Burstlen = 2 , Chanrpt = Enabled , Tci = Off , Eil = Off , Singleshot = Enabled , _
Sar = Burst , Sam = Inc , Dar = BLOCK , Dam = Inc , Trigger = &H10 , Btc = 4000 , Repeat = 0 , Sadr = Varptr(adca_ch0_res) , Dadr = Varptr(samples(1)) |
|
|
Back to top |
|
|
Meister
Joined: 27 May 2010 Posts: 319
|
Posted: Thu Jul 30, 2015 7:11 pm Post subject: |
|
|
Hello MWS,
I was experimenting a lot with that code but everything else came out worse than that what I had posted.
Of course, it is less than satisfying not knowing exactly what is going on (the timings) but as long as it shows the expected results it might be ok.
To analyse the timings would be tedious.
I remember that a wise person time ago told me "If there is an uncured problem it will hit you at some occasion". Let's wait for that...
Why I did it? I was motivated by the recent DIY-Osci thread in the Bascom forum. It is easy to record nice signals, but to discover very noisy signals there are not so many solutions (except in some TEK oscilloscopes as far as I know). Of course, the signals have to be periodic like an echo on recurring event (light or sound pulse).
Meanwhile I got the Attiny85 delay-generator working - easy with Bascom - and I nicely can shift the accumulated signal on the time scale - back and forth.
As always, thanks for your help.
Regards, Meister |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Fri Jul 31, 2015 4:04 pm Post subject: |
|
|
Ok, then have it your way
To point out the initial question, which you thought helpful for others and which may give some meat to the thread for readers looking it up, here's the equivalent for this config:
Code: | Config Dmach0 = Enabled , Burstlen = 2 , Chanrpt = Disabled , Tci = Lo , Eil = Lo , Singleshot = Disabled , _
Sar = Burst , Sam = Inc , Dar = Block , Dam = Inc , Trigger = &H10 , Btc = 4000 , Repeat = 1 , Sadr = Varptr(adca_ch0_res) , Dadr = Varptr(samples(1))
|
Notice I have changed Dar, not having to reload it via code.
---->
Code: | ' Bitnames
Const ERRINTLVL_1 = 3
Const ERRINTLVL_0 = 2
Const TRNINTLVL_1 = 1
Const TRNINTLVL_0 = 0
Const SRCRELOAD_1 = 7
Const SRCRELOAD_0 = 6
Const SRCDIR_1 = 5
Const SRCDIR_0 = 4
Const DESTRELOAD_1 = 3
Const DESTRELOAD_0 = 2
Const DESTDIR_1 = 1
Const DESTDIR_0 = 0
Const DMA_CHEN = 7
Const DMA_CHRST = 6
Const DMA_REPEAT = 5
Const DMA_TRFREQ = 4
Const DMA_SINGLE = 2
Const DMA_BURSTLEN_1 = 1
Const DMA_BURSTLEN_0 = 0
DMA_CH0_TRFCNT = 4000
DMA_CH0_REPCNT = 1
DMA_CH0_SRCADDR = Varptr(adca_ch0_res)
DMA_CH0_DESTADDR = Varptr(samples(1))
DMA_CH0_CTRLB = Bits(ERRINTLVL_0 , TRNINTLVL_0)
DMA_CH0_ADDRCTRL = Bits(SRCRELOAD_1 , SRCDIR_0 , DESTRELOAD_0 , DESTDIR_0)
DMA_CH0_TRIGSRC = &H10
DMA_CH0_CTRLA = Bits(DMA_CHEN , DMA_BURSTLEN_0) |
But - if you write it this way, you gain nothing, code and runtime is equal to the config line.
This may change a bit, if after initial config (as above) only necessary registers are written for a restart, which would look like:
Code: | DMA_CH0_TRFCNT = 4000
DMA_CH0_CTRLA = Bits(DMA_CHEN , DMA_BURSTLEN_0) |
As far I understand the documentation TRFCNT will be only automatically reloaded in continuous mode, so for a single run it has to be reloaded via code.
After loading TRFCNT, re-enabling the channel should do the trick.
Try it out and report it here.
Again, as already stated: You gain a few cycles, which you are wasting by thousands in wait-cycles, but it still may be interesting from the academic POV. |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You cannot download files in this forum
|
|