As previously reported here http://www.matrixmultimedia.com/mmforum ... f=5&t=8622 and http://www.matrixmultimedia.com/mmforum ... 967#p38967 I had been struggling to get an interrupt triggered A/D on a PIC to speed up. Was partly solved with your help, v5 and a faster 8 bit processor.
Now I find that someone using an Arduino to do something similar to me suggests:
“I use a timer interrupt to drive the sample rate. The standard Arduino library ADC read function is blocking and takes over 110µs, which is most of the available 156µs sample period (interrupt time). So, the ADC read is split into 2 parts, start conversion, and read result. By reading the previous result then starting again in each timer interrupt, the conversion can take place in the background. This frees up the time required to get the ADC reading.” Not quite sure what he means by “blocking” but I assume it means nothing else can be done until that routine is finished which is the problem I have.
The core Arduino C code for this is:-
// kick off a slow conversion. Read it next interrupt.
i_adc.start_conversion();
// read ADC started on previous cycle.
const int i = i_adc.read();
although there are probably more lines that just those.
Do you think it would be difficult for me to alter the order of your C Code in your ADC_RAW_Sample_Channel_Int routine to read the result for the previous sample before starting a new one and jumping back to main code whilst it executes? It’s the 11 A/D clock cycles needed to convert the voltage that is the main cause of slow speed, but these would now be done in the background. Is there any reason why the PIC can not get on with sampling in the background and not be at all affected by foreground activities like other interrupts and the main code? I assume the register that stores the A/D result is not reused for other things in between A/D samples thus wiping the saved value.
As you suggested to speed it up I am not precharging the sampling capacitor every time as only measuring one A/D channel.
The C Code for RAW_Sample seems to be just one line:-
MX_UINT16 FCD_ADC1_ADC_RAW_Sample_Channel_Int()
{
return FC_CAL_Sample_ADC( 1 ); //Perform Sample - Return as MX_UINT16
So not much scope for reordering that into a different order.
ReadAsInt is more promising:-
MX_UINT16 FCD_ADC1_ReadAsInt()
{
MX_UINT16 retVal;
//Configure & Enable ADC Channel
FC_CAL_Enable_ADC ( ADC_3_MX_ADC_CHANNEL , ADC_3_MX_ADC_CONVSP , ADC_3_MX_ADC_VREFOP , ADC_3_MX_ADC_ACTIME );
retVal = FC_CAL_Sample_ADC( 1 ); //Perform Sample - Return as MX_UINT16
FC_CAL_Disable_ADC ();
return (retVal)
but not clear how to start the sampling going and jump back to main loop as FC_CAL_Sample_ADC presumably does it all and won’t allow anything else to happen until the sampling is finished.
What exactly is the difference between a RAW_Sample and a ReadAsInt?
A/D speed
Moderator: Benj
- 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
Hello,
The CAL (code abstraction layer) for the ADC works like this.
1) Enable ADC - Setup up the ADC channel and performs pre-charge.
2) Sample ADC - Starts the conversion process, waits for end and returns sample.
3) Disable ADC - Restores the pin back to the previous digital state.
RAW_Sample calls item 2 whereas ReadAsInt calls 123.
The block you wish to split up is block 2. One easy way would be to move the code that starts the conversion out of the CAL C code file and this way it will still check to see if the conversion is complete before grabbing the data.
Here is a example CAL function in the AVR_ADC_CAL file, the actual function you edit should be correct for the MX_ADC_TYPE definition for your target.
Cut this line from the function and save the file.
Then add the line of C code directly into Flowcode via a C icon.
To collect the result simply continue calling the function RAW_Sample and this will check the conversion is complete before passing back the sample value.
Hope this helps.
The CAL (code abstraction layer) for the ADC works like this.
1) Enable ADC - Setup up the ADC channel and performs pre-charge.
2) Sample ADC - Starts the conversion process, waits for end and returns sample.
3) Disable ADC - Restores the pin back to the previous digital state.
RAW_Sample calls item 2 whereas ReadAsInt calls 123.
The block you wish to split up is block 2. One easy way would be to move the code that starts the conversion out of the CAL C code file and this way it will still check to see if the conversion is complete before grabbing the data.
Here is a example CAL function in the AVR_ADC_CAL file, the actual function you edit should be correct for the MX_ADC_TYPE definition for your target.
Code: Select all
MX_UINT16 FC_CAL_Sample_ADC (MX_UINT8 Sample_Mode)
{
MX_UINT16 iRetVal;
AD1CON1bits.SAMP = 0; //begin conversion and wait until it has finished
while (!AD1CON1bits.DONE);
if (Sample_Mode)
{
iRetVal = ADC1BUF0; //12-bit ADC
}
else
iRetVal = (ADC1BUF0 >> 4); //8-bit ADC
AD1CON1bits.SAMP = 1;
return (iRetVal);
}
Code: Select all
AD1CON1bits.SAMP = 0; //begin conversion and wait until it has finished
Code: Select all
AD1CON1bits.SAMP = 0; //Starts the conversion
Hope this helps.
Regards Ben Rowland - MatrixTSL
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
Re: A/D speed
Thank you, that looks promising. I tried it quickly and it did return a value for the voltage. It was not the correct one but I think though that is a bug in my software and not a fault with your suggested change.
In the PIC_CAL_ADC file for my type 19 PIC it says:-
MX_UINT16 FC_CAL_Sample_ADC (MX_UINT8 Sample_Mode)
{
MX_UINT16 iRetVal;
adcon0 = adcon0 | 0x02; //begin conversion and wait until it has finished
while (adcon0 & 0x02);
if (Sample_Mode)
{
iRetVal = (adresh << 2); //10-bit ADC
iRetVal = iRetVal | (adresl >> 6);
So I only need to cut from it
adcon0 = adcon0 | 0x02;
Now my routine is
Interrupt triggers and interrupt macro starts
variable = RAW_Sample // read the last value using modified CAL file
adcon0 = adcon0 | 0x02; //begin conversion
end of macro
go and do other stuff till next interrupt (This always takes much longer than 11 A/D cycles so conversion never not finished.)
Are you sure that the end of the macro occurs at the beginning of the conversion and it does not need to wait the full 11 A/D cycles before the macro can end?
I assume this change does not upset the ability of the code to return the value to the actual variable I have allocated to it.
Do I have to reboot Flowcode as well as recompile the code to get the change accepted?
That all should cut the A/D times to well less than half what it was before and make my previously rather lengthy interrupt macro less of a risk to conflicting with other stuff.
In the PIC_CAL_ADC file for my type 19 PIC it says:-
MX_UINT16 FC_CAL_Sample_ADC (MX_UINT8 Sample_Mode)
{
MX_UINT16 iRetVal;
adcon0 = adcon0 | 0x02; //begin conversion and wait until it has finished
while (adcon0 & 0x02);
if (Sample_Mode)
{
iRetVal = (adresh << 2); //10-bit ADC
iRetVal = iRetVal | (adresl >> 6);
So I only need to cut from it
adcon0 = adcon0 | 0x02;
Now my routine is
Interrupt triggers and interrupt macro starts
variable = RAW_Sample // read the last value using modified CAL file
adcon0 = adcon0 | 0x02; //begin conversion
end of macro
go and do other stuff till next interrupt (This always takes much longer than 11 A/D cycles so conversion never not finished.)
Are you sure that the end of the macro occurs at the beginning of the conversion and it does not need to wait the full 11 A/D cycles before the macro can end?
I assume this change does not upset the ability of the code to return the value to the actual variable I have allocated to it.
Do I have to reboot Flowcode as well as recompile the code to get the change accepted?
That all should cut the A/D times to well less than half what it was before and make my previously rather lengthy interrupt macro less of a risk to conflicting with other stuff.
- 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
Yes once the ADC has been started it will control itself regardless of what your program is doing.Are you sure that the end of the macro occurs at the beginning of the conversion and it does not need to wait the full 11 A/D cycles before the macro can end?
Nope you shouldn't have any issues with this.I assume this change does not upset the ability of the code to return the value to the actual variable I have allocated to it.
Code from the CAL files is automatically re-compiled when Flowcode compiles. You may have to hold the Left shift when clicking compile to chip to get Flowcode to recompile the code rather then simply programming the target with the firmware it thinks is up to date.Do I have to reboot Flowcode as well as recompile the code to get the change accepted?
Let me know how you get on.
Regards Ben Rowland - MatrixTSL
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
Re: A/D speed
It was my bug. Now all OK. Changing from Flowcode v3 and a 20Mhz clock speed to 64Mhz in v5 and its additional options of ADC clock speed and the simplified RAW Sample reduced the ADC time from 58us to 14us. Now it’s down to less than 4us with this new change as the 11 A/D clock cycles, taking a nominal 11us, have gone into background processing. Have now halved the A/D clock rate and added some acquisition time to further guarantee the conversion accuracy and that makes no difference to the overall code speed as all done in background.echase wrote: I tried it quickly and it did return a value for the voltage. It was not the correct one but I think though that is a bug in my software .
This option to optionally push it to background might be worth considering as a future Flowcode enhancement although might be a bit tricky to arrange. Also have to remember that samples are arriving later.
So I am really happy. Even better if I could remove some maths from that interrupt macro too but failing a maths coprocessor to perform some maths in parallel with main processor I can’t see that being possible.