A/D speed up

For Flowcode users to discuss projects, flowcharts, and any other issues related to Flowcode 2 and 3.

Moderators: Benj, Mods

Post Reply
echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

A/D speed up

Post by echase »

In http://ww1.microchip.com/downloads/en/D ... 31023a.pdf it implies that you need to set up some parameters/registers like ADCS to set the conversion times. What times have you set, where are they set and is it realistic for me to change them to speed up the A/D? Quite like to halve the time it is currently taking and don’t mind if I get slight loss of accuracy as a result.

I am using a 16F690 at 20MHz with Flowcode v3.

Table 23-1 of this doc and the 690 datasheet implies that at 20MhHz I need to run at Fosc/32 . Can I put a C Code line in to set ADCS to 010 for this that permanently overwrites any default you have set? I.e. I don’t have to keep resetting ADCS at every conversion.

There is long discussion of setting the right TACQ time but not clear how Flowcode sets the time to ensure say 20usec is allowed for acquisition. Can I change it?

With TACQ at 20us and TAD at Fosc/32 (1.6us) I can do a whole A/D sample in about 20 +11 x 1.6 = 37.6us which is OKish but I wonder what Flowcode defaults are giving me? I have to do 2 A/Ds and some calculation all in well under my 500us interrupt time.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

Re: A/D speed up

Post by echase »

I have now measured the time with a ‘scope and it takes 85us to do the Flowcode sample command and very aprox 5us to do the Flowcode read the result as an integer. As 85 is roughly twice the 37.6 above I suspect you have set it to Fosc/64 and/or set a very slow TACQ. How can I change these?

PS 1) I am using a lot of connection points to jump over unused code, in case I need to put it back later. Is the cut out code present in the C, ASM or Hex files? I assume it’s not clogging up the PIC memory.

2) Are LED macros slower than just using an Output command to turn on the PIC pin connected to the LED? But the latter approach does not enable a LED to show on screen during simulation.

3) Is there a website you could recommend that would give me guidance on code execution times, e.g. time to complete a calculation, output, LCD write, A/D, etc?

Although my ‘scope is useful it can’t capture the shorter times like 5us easily.

User avatar
Benj
Matrix Staff
Posts: 15312
Joined: Mon Oct 16, 2006 10:48 am
Location: Matrix TS Ltd
Has thanked: 4803 times
Been thanked: 4314 times
Contact:

Re: A/D speed up

Post by Benj »

Hello,

In answer to your questions.

There is a charge time associated with sampling an ADC channel. If you are only ever sampling a single channel then the charge time can be negated, if however you are sampling multiple channels then the charge time must be present or the channels will appear to bleed into each other.

1) The code that never gets executed should be optimized out. I say should because it really depends on the compiler but I think most C compilers will do this for you. I personally use decision icons with 0 as the parameter for commenting out sections of code. This way the compiler is sure the code will never be executed.

2) LED and Output commands are very similar and I wouldn't expect there is much difference between them.

3) Each assembler instruction will take ((1/clock speed)/4)seconds to execute on a standard 8-bit PIC. C code can be translated to assembler in a number of ways so its hard to give a precise figure. There is a casm file generated by Flowcode which shows you the C code plus Flowcode comments related to the Assembler code so you may be able to get specific timings from this.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

Re: A/D speed up

Post by echase »

Thanks but you did not specifically answer my question, “I suspect you have set it to Fosc/64 and/or set a very slow TACQ. How can I change these?” I want to set it to Fosc/32 and a TACQ of 20us as per the datasheet.

I am sampling 2 channels

User avatar
Benj
Matrix Staff
Posts: 15312
Joined: Mon Oct 16, 2006 10:48 am
Location: Matrix TS Ltd
Has thanked: 4803 times
Been thanked: 4314 times
Contact:

Re: A/D speed up

Post by Benj »

Hello,

For Flowcode v3 the ADC sample routine is located in the FCD file. The best way is probably to edit the FCD manually.

For the 16F690 device the ADC section of the FCD looks like this.

Code: Select all

ADCCapture="//set up ADC conversion\nchar old_tris, cnt;\n#define MX_ADC_SAMP_TIME 40\nadcon1 = 0x20;\n\n//find appropriate bit\n#if (%a == 0)\n  #define MX_ADC_TRIS_REG  trisa\n  #define MX_ADC_TRIS_MSK  0x01\n  ansel = 0x01;\n#endif\n#if (%a == 1)\n  #define MX_ADC_TRIS_REG  trisa\n  #define MX_ADC_TRIS_MSK  0x02\n  ansel = 0x02;\n#endif\n#if (%a == 2)\n  #define MX_ADC_TRIS_REG  trisa\n  #define MX_ADC_TRIS_MSK  0x04\n  ansel = 0x04;\n#endif\n#if (%a == 3)\n  #define MX_ADC_TRIS_REG  trisa\n  #define MX_ADC_TRIS_MSK  0x10\n  ansel = 0x08;\n#endif\n#if (%a == 4)\n  #define MX_ADC_TRIS_REG  trisc\n  #define MX_ADC_TRIS_MSK  0x01\n  ansel = 0x10;\n#endif\n#if (%a == 5)\n  #define MX_ADC_TRIS_REG  trisc\n  #define MX_ADC_TRIS_MSK  0x02\n  ansel = 0x20;\n#endif\n#if (%a == 6)\n  #define MX_ADC_TRIS_REG  trisc\n  #define MX_ADC_TRIS_MSK  0x04\n  ansel = 0x40;\n#endif\n#if (%a == 7)\n  #define MX_ADC_TRIS_REG  trisc\n  #define MX_ADC_TRIS_MSK  0x08\n  ansel = 0x80;\n#endif\n#if (%a == 8)\n  #define MX_ADC_TRIS_REG  trisc\n  #define MX_ADC_TRIS_MSK  0x40\n  anselh = 0x01;\n#endif\n#if (%a == 9)\n  #define MX_ADC_TRIS_REG  trisc\n  #define MX_ADC_TRIS_MSK  0x80\n  anselh = 0x02;\n#endif\n#if (%a == 10)\n  #define MX_ADC_TRIS_REG  trisb\n  #define MX_ADC_TRIS_MSK  0x10\n  anselh = 0x04;\n#endif\n#if (%a == 11)\n  #define MX_ADC_TRIS_REG  trisb\n  #define MX_ADC_TRIS_MSK  0x20\n  anselh = 0x08;\n#endif\n\n//sanity check\n#ifndef MX_ADC_TRIS_REG\n  #pragma error ADC conversion code error - please contact technical support\n#endif\n \n//store old tris value, and set the i/o pin as an input\nold_tris = MX_ADC_TRIS_REG;\nMX_ADC_TRIS_REG = MX_ADC_TRIS_REG | MX_ADC_TRIS_MSK;\n \n//turn ADC on\nadcon0 = 0x01 | (%a << 2);\n\n//wait the acquisition time\ncnt = 0;\nwhile (cnt < MX_ADC_SAMP_TIME) cnt++;\n \n//begin conversion and wait until it has finished\nadcon0 = adcon0 | 0x02;\nwhile (adcon0 & 0x02);\n\n//restore old tris value, and reset adc registers\nMX_ADC_TRIS_REG = old_tris;\nansel = 0;\nanselh = 0;\nadcon0 = 0x00;\n#undef MX_ADC_TRIS_REG\n#undef MX_ADC_TRIS_MSK\n#undef MX_ADC_SAMP_TIME\n"

ADCHigh="return adresh;\n"

ADCLow="char adclow;\nadclow = adresl;\nreturn adclow;\n"

ADCFull="short iRetVal;\niRetVal = (adresh << 2);\niRetVal += (adresl >> 6);\nreturn (iRetVal);\n"
If you wish to make the contents more readable then you can use TextPad or another text editor to search for \\n and replace for \n. you will then have to reverse the process when converting back to the FCD syntax.

Here is the sample routine with the newlines in place,

Code: Select all

ADCCapture="//set up ADC conversion
char old_tris, cnt;
#define MX_ADC_SAMP_TIME 40
adcon1 = 0x20;

//find appropriate bit
#if (%a == 0)
  #define MX_ADC_TRIS_REG  trisa
  #define MX_ADC_TRIS_MSK  0x01
  ansel = 0x01;
#endif
#if (%a == 1)
  #define MX_ADC_TRIS_REG  trisa
  #define MX_ADC_TRIS_MSK  0x02
  ansel = 0x02;
#endif
#if (%a == 2)
  #define MX_ADC_TRIS_REG  trisa
  #define MX_ADC_TRIS_MSK  0x04
  ansel = 0x04;
#endif
#if (%a == 3)
  #define MX_ADC_TRIS_REG  trisa
  #define MX_ADC_TRIS_MSK  0x10
  ansel = 0x08;
#endif
#if (%a == 4)
  #define MX_ADC_TRIS_REG  trisc
  #define MX_ADC_TRIS_MSK  0x01
  ansel = 0x10;
#endif
#if (%a == 5)
  #define MX_ADC_TRIS_REG  trisc
  #define MX_ADC_TRIS_MSK  0x02
  ansel = 0x20;
#endif
#if (%a == 6)
  #define MX_ADC_TRIS_REG  trisc
  #define MX_ADC_TRIS_MSK  0x04
  ansel = 0x40;
#endif
#if (%a == 7)
  #define MX_ADC_TRIS_REG  trisc
  #define MX_ADC_TRIS_MSK  0x08
  ansel = 0x80;
#endif
#if (%a == 8)
  #define MX_ADC_TRIS_REG  trisc
  #define MX_ADC_TRIS_MSK  0x40
  anselh = 0x01;
#endif
#if (%a == 9)
  #define MX_ADC_TRIS_REG  trisc
  #define MX_ADC_TRIS_MSK  0x80
  anselh = 0x02;
#endif
#if (%a == 10)
  #define MX_ADC_TRIS_REG  trisb
  #define MX_ADC_TRIS_MSK  0x10
  anselh = 0x04;
#endif
#if (%a == 11)
  #define MX_ADC_TRIS_REG  trisb
  #define MX_ADC_TRIS_MSK  0x20
  anselh = 0x08;
#endif

//sanity check
#ifndef MX_ADC_TRIS_REG
  #pragma error ADC conversion code error - please contact technical support
#endif
 
//store old tris value, and set the i/o pin as an input
old_tris = MX_ADC_TRIS_REG;
MX_ADC_TRIS_REG = MX_ADC_TRIS_REG | MX_ADC_TRIS_MSK;
 
//turn ADC on
adcon0 = 0x01 | (%a << 2);

//wait the acquisition time
cnt = 0;
while (cnt < MX_ADC_SAMP_TIME) cnt++;
 
//begin conversion and wait until it has finished
adcon0 = adcon0 | 0x02;
while (adcon0 & 0x02);

//restore old tris value, and reset adc registers
MX_ADC_TRIS_REG = old_tris;
ansel = 0;
anselh = 0;
adcon0 = 0x00;
#undef MX_ADC_TRIS_REG
#undef MX_ADC_TRIS_MSK
#undef MX_ADC_SAMP_TIME
"
For this device editing these lines should be enough to allow for the faster conversion time.

Code: Select all

adcon1 = 0x20;      //Conversion Speed

#define MX_ADC_SAMP_TIME 40      //ADC Channel Charge Time

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

Re: A/D speed up

Post by echase »

Sorry I am being thick. Your adcon1 = 0x20 sets Fosc/32 as I want it, but it is already set to 0x20 in the existing 690 file so I can’t speed it up further.

Is #define MX_ADC_SAMP_TIME 40 the charge up time in usec? In which case I need to change the 40 default to 20.

So I am only overall going to shave off 20us (=40-20). That does not really explain the difference between the 85us I am measuring and the 37.6us ideal. Either I am measuring it wrongly (unlikely in this case) or maybe your code is not actually executing in anything like the ideal time (1.6us per TAD and needing 11 of them to complete the sample.) I assume you write the code for bullet-proof operation in all circumstances and not necessarily high speed, so I can understand if it’s not working quite as fast as it could.

User avatar
Benj
Matrix Staff
Posts: 15312
Joined: Mon Oct 16, 2006 10:48 am
Location: Matrix TS Ltd
Has thanked: 4803 times
Been thanked: 4314 times
Contact:

Re: A/D speed up

Post by Benj »

Hello,

The definition MX_ADC_SAMP_TIME is the number of iterations to wait while the ADC capacitor charges/discharges.

At the moment 40 cycles would give a delay of just over((clockspeed / 4) / 40) seconds.

You can play around with the time delay by changing the constant from 40.

The ADC code is actually written specifically for its intended device and as such is fairly efficient so I am surprised you are getting such long delays. Are you using say the LCD to print out your values which could be slowing down the program.

My guess is that the Microchip example in the datasheet does not take into account charge time but I could be wrong.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

Re: A/D speed up

Post by echase »

echase wrote:With TACQ at 20us and TAD at Fosc/32 (1.6us) I can do a whole A/D sample in about 20 +11 x 1.6 = 37.6us .
That formula is from the datasheet and includes the aquisition time (at 50C where it needs to be 1us longer). They say aquisition time for all Mid Range devices should be around >=20us with high impedance inputs and >=10us with low ones.

Based on your formula the cycle period is 1/(20/4) = 0.2us. So 40 of these takes a mere 8us. So TACQ is already under the minimum specified. It would be fine at clock speeds under 10MHz but at my 20MHz it’s too short already.

So again it is not giving me any opportunity to shorten the total A/D time which further makes me suspect the efficiency of your code, e.g. what are all those 12 blocks of

#if (%a == 5)
#define MX_ADC_TRIS_REG trisc
#define MX_ADC_TRIS_MSK 0x02
ansel = 0x20;
#endif

doing? Are they slowing it down? (Probably not much because I see that the ASM for all this is only 4 lines.) Are they executed at every sample?

No I am not using the LCD at this stage. To get the 85us I, all in Flowcode icons/macros:

Set pin A1 to 1
Do sample on ADC11
Set pin A1 to 0.
Read as integer

So with 'scope on pin A1 I measured 85us. The A1 lines add about 12us so the sample line takes 73us. I did what you suggested above and counted ASM lines in the CASM file and arrived at a sample time of about 67us so that agrees pretty well with the 'scope.

By later altering the position of the A1 lines I also measured the read as integer line at about 5us. But counting ASM lines gives 40us, which seems wrong. I suspect I am misinterpreting the CASM file which has 3 blocks of code for this macro and maybe only one short block is actually used.

(Interesting that my previous project, which was using a slow 32kHz clock, must have had a TACQ of a large 5 ms, although it was a 2520 processor and so you might have set a slightly different MX_ADC_SAMP_TIME. I wonder if too long a time is a problem? Could you not instead set a fixed time for TACQ [say 20us] that is not clock speed dependent, especially as some PICs have clock speeds even greater than 20MHz?)

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

Re: A/D speed up

Post by echase »

echase wrote:
Based on your formula the cycle period is 1/(20/4) = 0.2us. So 40 of these takes a mere 8us.
I have measured this again and I am not convinced that one MX_ADC_SAMP_TIME is 0.2us. Instead my ‘scope says it is around 1.25us (by increasing MX_ADC_SAMP_TIME by 20 to give a good added length to measure). I have now changed my 690 FCD to change the MX_ADC_SAMP_TIME to 12 (15us) instead of 40 and it works fine. It would not work if one MX_ADC_SAMP_TIME was really 0.2us.

The ASM code for the wait loop is

//wait the acquisition time
cnt = 0;
00F1 01E5 CLRF FCD_ADC0_S_00027_1_cnt

while (cnt < MX_ADC_SAMP_TIME) cnt++;
00F2 label268440604
00F2 3028 MOVLW 0x28
00F3 0265 SUBWF FCD_ADC0_S_00027_1_cnt, W
00F4 1803 BTFSC STATUS,C
00F5 28F8 GOTO label268440605
00F6 0AE5 INCF FCD_ADC0_S_00027_1_cnt, F
00F7 28F2 GOTO label268440604
00F8 label268440605

I make that at least 5 lines (each 0.2us) for the loop and longer if SUBWF is some kind of delay subroutine. So it’s nearer my measured 1.25us than 0.2us.

Beware any other readers of this thread as some of the thread erroneously uses 1.25 when it should be 0.2 and vice versa. I thought some of it was a bit strange!

User avatar
Benj
Matrix Staff
Posts: 15312
Joined: Mon Oct 16, 2006 10:48 am
Location: Matrix TS Ltd
Has thanked: 4803 times
Been thanked: 4314 times
Contact:

Re: A/D speed up

Post by Benj »

Hello,

Yes I see that my calculation for the timing was well off. For the v5 ADC component I will make the transition to a time delay rather then the current number of cycles around the loop and hopefully this will make getting the charge time correct much easier.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times
Contact:

Re: A/D speed up

Post by echase »

Great suggestion. A fixed time delay of 20us should cover all applications of Mid Range devices. Don’t know about other ranges but I doubt they are much different.

Post Reply