View previous topic :: View next topic |
Author |
Message |
Ruprecht
Joined: 21 Jul 2005 Posts: 88 Location: Czech Republic
|
|
Back to top |
|
|
Meister
Joined: 27 May 2010 Posts: 319
|
Posted: Mon Apr 27, 2015 9:12 pm Post subject: |
|
|
There are examples in the BASCOM "Samples" directory. For instance, look for "adc.bas".
That works. |
|
Back to top |
|
|
Ruprecht
Joined: 21 Jul 2005 Posts: 88 Location: Czech Republic
|
Posted: Tue Apr 28, 2015 6:28 am Post subject: |
|
|
Thanks for answer but it is not what I want.
"adc.bas" works in single mode (slow), "adc_int.bas" works in free mode but using interrupt.
What I need is ADC in free mode without interrupts and without waiting for end of conversion.
I think here http://www.mcselec.com/index2.php?option=com_forum&Itemid=59&page=viewtopic&t=9374&highlight=adc+free is what I need:
Quote: | the big advantage of free mode is, that the ADC samples in the background instead having you waiting for end of conversion.
Nobody tells you have to use free running with ADC interrupt
You can have it free running and simply read out the least current result., whenever you like. It only costs the time then to read out ADCH, which will be less than 1µs.
However all depends on your requirements, whether for example the least current result is good enough, or if the result has to be read at an exact specified time in your code.
If you use a prescaler of 16, then it takes 16 * 13 cycles for each conversion, that's 208 cycles, and that's 11.3µs which corresponds pretty well with your 12.5µs. If you wait for it, it blocks your code for that time.
In case you do a series of samples, you won't get any faster either, as that's simply the ADC limits.
Only if at some time in your code you need a result as fast as possible, then simply reading out ADCH in free running mode could do. |
But I cannot reach this |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Apr 28, 2015 8:26 am Post subject: |
|
|
Ruprecht wrote: | But I cannot reach this |
Because you lack basic understanding how free-run works.
Also in free-run there's a conversion time, the same as in single mode, so one still has to wait till the conversion is ready.
So this
Code: | Admux = 5
Adclow = Adcl
Adchigh = Adch |
is complete nonsense.
As more as it kills partly this line:
Code: | Config Adc = Free , Prescaler = Auto , Reference = Avcc |
by clearing REFS0 and setting Reference to external.
To do free-run mode without ISR is much more complex, if more than one channel is involved.
If you would consult the data sheet
Quote: | In Free Running mode, always select the channel before starting the first conversion. The chan-
nel selection may be changed one ADC clock cycle after writing one to ADSC. However, the
simplest method is to wait for the first conversion to complete, and then change the channel
selection. Since the next conversion has already started automatically, the next result will reflect
the previous channel selection. Subsequent conversions will reflect the new channel selection. |
you'd learn that it depends on when the main-loop is able to read ADC.
The problem is asynchronous handling of the result in the main loop, it's difficult to say to what MUX-setting the result belongs to.
If the time between setting MUX and reading ADC is longer than two ADC-conversions, the result always belongs to the actual MUX-setting, otherwise it may belong to the previous setting.
That is also the reason, you'll find little information for your approach
Quote: | What I need is ADC in free mode without interrupts and without waiting for end of conversion. |
as it's unsuitable, if you need to switch channels.
In an ISR the MUX-switching can be done in a controlled way, considered the ADC-ISR is not blocked by another ISR for too long.
Then simply the actual result belongs to the previous MUX-setting.
However, if free-run is done with only one channel (like in the link you've posted), the problem doesn't occur, one simply reads ADC and always gets the last valid result.
With repeatedly changing MUX, it's much different.
Better describe what you want to achieve and why without ISR, than describing an unsuitable approach. |
|
Back to top |
|
|
Meister
Joined: 27 May 2010 Posts: 319
|
Posted: Tue Apr 28, 2015 8:35 am Post subject: |
|
|
Have you tried change "single" to free in adc.bas?
In Attiny841 I use
Code: | Admuxa = &B0010_1011' Differential
Adcsra = &B1111_0101' 'Auto Trigger enable (Bit5)
Adcsrb = 0 'Free Running mode
W1 = Adc
If W1.9 = 1 Then W1 = W1 Or &HFE00 'for negative values
|
No interrupts. |
|
Back to top |
|
|
Ruprecht
Joined: 21 Jul 2005 Posts: 88 Location: Czech Republic
|
Posted: Wed Apr 29, 2015 11:34 am Post subject: |
|
|
Quote: | Better describe what you want to achieve and why without ISR, than describing an unsuitable approach. |
Ok, let me explain:
Three wavetables, HW SPI feeding DAC at 2,5kHz up to 35kHz, driven by Timer1 interrupt.
One pot changes play speed (by changing T1 value), second pot is for table selection.
There is not enough time to ordinary single ADC conversion, every 28us must be new sample sent to DAC in worst case.
I need not sample ADCs in every program loop so I thought about such solution:
- set adcmux to ch3 (speed)
- after say 2-4 program loops (to be sure values in ADCL and ADCH are valid for ch3) read ADCL and ADCH
- set adcmux to ch5 (table select)
- after say 2-4 program loops read ADCL and ADCH (ch5)
No sample should be lost or delayed so Timer1 interrupt and SPI out are most important things. |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Wed Apr 29, 2015 12:22 pm Post subject: |
|
|
Ruprecht wrote: | - set adcmux to ch3 (speed)
- after say 2-4 program loops (to be sure values in ADCL and ADCH are valid for ch3) read ADCL and ADCH
- set adcmux to ch5 (table select)
- after say 2-4 program loops read ADCL and ADCH (ch5) |
That will work, if the 2-4 loops are longer than 2 * 13.5 * ADC-prescaler clocks.
If ADC is read then, the result clearly belongs to the previously set MUX.
Be careful not to overwrite other bits in the ADMUX register.
Afair it should work to set the MUX with a (dummy) read of GetADC(chan).
GetADC() in single-mode does 2 ADC-reads and blocks program execution as long as a 2-times conversion takes, in free-run however it does not block, returns only the value of
ADC and sets MUX.
To have better control, I'd calculate the ADC-prescaler myself according the datasheet, so I'd know how many clocks my program-loops have to be.
In AUTO the ADC-prescaler is likely set (depending on main clock) to 256, so to be safe, your program-loops should take 2 * 13.5 * 256 = 6912 cpu-clocks.
The factor 13.5 results out of ADC-clocks (after the ADC-prescaler) required for one conversion. |
|
Back to top |
|
|
Ruprecht
Joined: 21 Jul 2005 Posts: 88 Location: Czech Republic
|
Posted: Wed Apr 29, 2015 2:56 pm Post subject: |
|
|
Really thank you, you brought me out of darkness... I hope
After some time with datasheet I think this setup will be correct:
Code: |
'Setting MUX to ADC3 before starting first concersion:
ADMUX = &b0100_0011 '(7,6: AVcc + cap, 5: right adj., 4: reserved, 3-1: ADC3)
ADCSRA = &b1110_0111 '(7: AD enable, 6: AD start, 5: autotrig, 4: interrupt flag, 3: no interrupt, 2-0: prescaler = 128 (20MHz Xtal/128 = 156k ADC clock))
ADCSRB = &b0000_0000 '(7: reserved, 6: no comparator, 5-3: reserved, 2-0: free running mode)
'----in-main-loop------------------------------------------------------------------------
'Switching MUX to ADC3 in main loop:
ADMUX = &b0100_0011 '(7,6: AVcc + cap, 5: right adj., 4: reserved, 3-1: ADC3)
'then after some loops switch to ADC5:
ADMUX = &b0100_0101 '(7,6: AVcc + cap, 5: right adj., 4: reserved, 3-1: ADC5)
'and after some loops back to ADC3 and so on
|
Or overlooked something?
Thank you |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Wed Apr 29, 2015 4:17 pm Post subject: |
|
|
Ruprecht wrote: | Or overlooked something? |
Try to reduce the prescaler, if you attach pots you likely won't need 10bit resolution.
Prescaler 64 and main clock 20MHz gives you 312,5kHz ADC-clock, while it is above of 50-200kHz, which is described best in regards of resolution, it may be still suitable for manual inputs like pots.
I did not check your bit-notations for correctness, anyway I don't like this:
Code: | ADMUX = &b0100_0011 |
as it's error prone, better is:
Code: | ADMUX = Bits(REFS0, MUX1, MUX0) |
because the meaning is obvious.
Changing the channel is usually done this way:
Code: | ADMUX = ADMUX And NBits(MUX3, MUX2, MUX1, MUX0)
ADMUX = ADMUX Or channel |
But as said, I believe you can simply use Bascom's built-in commands, configure the ADC with FREE and then use GetADC(), which is compiled differently by using FREE, it will work non-blocking then, in the same it will set MUX and reads ADC.
Pseudo-code, not tested:
Code: | start:
ch2val = GetADC(chan1) ' dummy read, set MUX to chan1
Do
' wait for 1728 (2 * 13.5 * 64) cycles passing by
ch1val = GetADC(chan2) ' get converted value for previous MUX-setting (chan1) and set new MUX (chan2)
' wait for 1728 (2 * 13.5 * 64) cycles passing by
ch2val = GetADC(chan1) ' vice versa
Loop |
|
|
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
|
|